大对象堆碎片会导致 64 位进程中的 OutOfMemory 吗?

Nah*_*man 5 .net c# memory garbage-collection large-object-heap

我正在准备向我的团队介绍 .net GC 和内存。不同的来源讨论了碎片对大对象堆的潜在影响。由于这将是一个有趣的现象,我试图在代码中展示它。

Thomas Weller 提供了这段代码,当尝试将更大的对象分配到 LOH 中的已释放间隙时,它看起来应该会导致 OOM,但由于某种原因它没有发生。LOH 是否在 .net 4.6 中自动压缩?LOH 碎片在 64 位中根本就不是问题吗?

来源:https : //stackoverflow.com/a/30361185/3374994

class Program
{
    static IList<byte[]> small = new List<byte[]>();
    static IList<byte[]> big = new List<byte[]>(); 

static void Main()
{
    int totalMB = 0;
    try
    {
        Console.WriteLine("Allocating memory...");
        while (true)
        {
            big.Add(new byte[10*1024*1024]);
            small.Add(new byte[85000-3*IntPtr.Size]);
            totalMB += 10;
            Console.WriteLine("{0} MB allocated", totalMB);
        }
    }
    catch (OutOfMemoryException)
    {
        Console.WriteLine("Memory is full now. Attach and debug if you like. Press Enter when done.");
        Console.WriteLine("For WinDbg, try `!address -summary` and  `!dumpheap -stat`.");
        Console.ReadLine();

        big.Clear();
        GC.Collect();
        Console.WriteLine("Lots of memory has been freed. Check again with the same commands.");
        Console.ReadLine();

        try
        {
            big.Add(new byte[20*1024*1024]);
        }
        catch(OutOfMemoryException)
        {
            Console.WriteLine("It was not possible to allocate 20 MB although {0} MB are free.", totalMB);
            Console.ReadLine();
        }
    }
}
}
Run Code Online (Sandbox Code Playgroud)

Cod*_*ist 3

自 .NET 4.5.1(也是 .NET Core)以来,支持 LOH 压缩,并且可以通过GCSettings.LargeObjectHeapCompactionMode静态类GcSettings的属性来设置行为。

这意味着 LOH被 GC 压缩。

请注意,32 位进程对可以使用的内存量有一些限制,因此更有可能遇到 OOM 异常。

  • 谢谢!尽管据我了解,这种压缩必须在代码中设置,并且默认情况下不启用。所以我仍然不明白为什么代码示例在释放大块然后尝试设置一个大于释放间隙的新块后无法导致 OOM。来源:https://msdn.microsoft.com/en-us/library/system.runtime.gcsettings.largeobjectheapcompactionmode(v=vs.110).aspx (2认同)