64位进程中LOH碎片会引发OOM吗?.NET GC演示代码疑问
Great question—let’s break this down step by step to explain why your code isn’t hitting the expected OutOfMemoryException, and address your core questions about LOH behavior in .NET 4.6 and 64-bit environments.
Does .NET 4.6 automatically compact the LOH?
Back in .NET 4.5.1, the runtime added optional LOH compaction via the GCSettings.LargeObjectHeapCompactionMode property. In .NET 4.6 and later, this behavior got a key update:
- By default, the runtime will automatically compact the LOH during a full garbage collection when system memory pressure is high, or when you explicitly trigger it (like setting
GCLargeObjectHeapCompactionMode.CompactOncebefore callingGC.Collect()). - In your code, after clearing the
biglist and runningGC.Collect(), the .NET 4.6+ runtime likely performed LOH compaction. This merged the scattered 10MB free blocks into a single contiguous chunk—making the subsequent 20MB allocation possible, so noOutOfMemoryExceptionwas thrown.
Is LOH fragmentation no longer a problem in 64-bit environments?
No, it’s not gone—but it’s far less likely to cause immediate failures compared to 32-bit systems:
- 32-bit processes have a tiny 4GB address space (usually only 2GB available for user-mode code). Even small amounts of LOH fragmentation can quickly eat up all contiguous memory blocks needed for large objects.
- 64-bit processes have a massive address space (theoretical 16EB, with practical limits like 256GB on Windows Server). This means there’s way more room to allocate non-contiguous blocks, so fragmentation takes much longer to become critical.
- That said, long-running apps (like background services) that repeatedly allocate and free large objects of varying sizes can still accumulate LOH fragmentation over time. Eventually, this can lead to
OutOfMemoryExceptionwhen a sufficiently large contiguous block can’t be found.
Why isn’t your code triggering the expected OutOfMemoryException?
Your test relies on LOH fragmentation blocking a 20MB allocation after freeing multiple 10MB blocks. Here’s why it’s not working in .NET 4.6 64-bit:
- The automatic LOH compaction in .NET 4.6+ is fixing the fragmentation when you call
GC.Collect(), turning scattered free space into a single usable block. - To reproduce the original fragmentation behavior, you need to disable automatic compaction. Add this line right before
GC.Collect():
With this setting, the LOH won’t be compacted during the full GC. The scattered free space won’t be merged, and the 20MB allocation will fail withGCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.None;OutOfMemoryExceptionas expected.
Quick Debugging Tips
You can verify LOH state with tools like WinDbg:
- Use
!dumpheap -statto check object distributions across heaps. - Use
!eeheap -gcto view heap segments and free space. - Use
!address -summaryto see overall memory usage and fragmentation.
内容的提问来源于stack exchange,提问作者Nahum Timerman

