I have to quibble here. Automatic garbage collection doesn't solve fragmentation issues, and often has the reverse effect.
As you explain, fragmentation happens because of memory being allocated then freed in a different order than they were allocated in, and this is even more common with automatic garbage collection.
Compiled languages with a predictable memory layout like C, C++, D and Rust are the only languages where you have a fighting chance of dealing with fragmentation should it become an issue.
----
Another tool to avoid memory fragmentation is an Arena, where all your memory is allocated out of one large contiguous block, and then freed as a block, not individually. This is particularly useful for items with a trivial constructor.
---
Thanks for a good read!