> it's [just] the freeing that causes memory fragmentation.
Nope. Consider for examle a microcontroller with 64K of address space, consisting of 32K of low RAM, 8K of ROM/MMIO, and 24K of high RAM. Allocate buffers of size 23K, 15K, and 15K. With a straightforward first-fit allocator[0], you'll put the 23K in low RAM, leaving 9K, put the first 15K in high RAM, leaving 9K there, and fail to allocate the second 15K, because even though you have 18K free, it's fragmented into two 9K regions.
If you'd allocated that memory statically, you could have put the 23K in high RAM, and the two 15Ks in low RAM, with 2K low and 1K high left over.
It's debatable whether the fragmentation is 'caused' by malloc itself or by the ROM region in the middle of the address space, but you never called free, so it's not caused by free.
0: Less naive allocation strategies take more work to 'trap' like this, but I can work out a example for best-fit or whatever if you're sceptical that this isn't just a problem specific to first-fit.