64位进程中,大对象堆碎片化是否会导致内存不足?

5
我正在为我的团队准备一份关于 .net GC 和内存的演示文稿。 不同的来源讨论了碎片对大对象堆(Large Object Heap)的潜在影响。 由于这将是一个有趣的现象,所以我试图在代码中展示它。
Thomas Weller提供了这段代码,看起来应该会在尝试将更大的对象分配到LOH中释放的间隙时导致OOM,但出于某种原因它并没有发生。 .NET 4.6自动压缩LOH吗? 64位系统下LOH碎片化是否不是问题?
来源: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();
        }
    }
}
}
2个回答

3
自 .NET 4.5.1(也适用于.NET Core)开始支持LOH压缩,并且该行为可以通过静态类GcSettingsGCSettings.LargeObjectHeapCompactionMode属性进行设置。
这意味着GC会压缩LOH。
请注意,32位进程在可使用的内存量上存在一定限制,因此更容易遇到OOM异常。

2
虽然我理解这种压缩必须在代码中设置,而且默认情况下不会启用。所以我仍然不明白为什么代码示例在释放大块后尝试设置一个比释放的间隙更大的新块时无法引起OOM。来源:https://msdn.microsoft.com/en-us/library/system.runtime.gcsettings.largeobjectheapcompactionmode(v=vs.110).aspx - Nahum Timerman

1
我的猜测是,LOH不会自动压缩。
由于压缩LOH会影响性能,我们应该在确定时才进行压缩。
使用此代码,它将很快耗尽内存,压缩操作仅回收未被引用的对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接