A year ago, I research similar memory issues in Ruby. The established hypothesis in the community was that it was due to memory fragmentation. But I found that the largest culprit was actually the glibc memory allocator, which doesn't like to return memory to the OS. In multithreaded scenarios this issue is amplified even more, due to the use of separate heap arenas per thread.<p>I also found a simple solution: call malloc_trim() after a GC. This reduces memory usage by 70%.<p><a href="https://www.joyfulbikeshedding.com/blog/2019-03-14-what-causes-ruby-memory-bloat.html" rel="nofollow">https://www.joyfulbikeshedding.com/blog/2019-03-14-what-caus...</a>
Having written Haskell for over a year now for personal projects, understanding the memory model can be one of the hardest aspects of Haskell, which can make it frustrating to write allocation-free code (although some techniques like deforestation are done by the compiler to eliminate intermediate structures entirely).<p>Linear types being added in GHC 8.12 would be a big deal because it would allow programmers to be able to write allocation-free code that can use mutable data structures with a pure API (as opposed to the ST state monad), much like how Rust solves this with the ownership system.
Is this sort of multi-tier allocation used in any other garbage collected languages? Or is it specifically used in Haskell because of immutability (which would presumably to result in a higher-than-normal frequency of allocation/deallocation)?
Wouldn't the GC be able to `munmap` the space between blocks?<p>Sure, it wouldn't solve object-level fragmentation, but at least you'd get rid of block-level fragmentation.