C# 在64位进程中,大型对象堆碎片会导致OutOfMemory吗?

C# 在64位进程中,大型对象堆碎片会导致OutOfMemory吗?,c#,.net,memory,garbage-collection,large-object-heap,C#,.net,Memory,Garbage Collection,Large Object Heap,我正在为我的团队准备一个关于.NETGC和内存的演示。 不同来源讨论了碎片对大型对象堆的潜在影响。 因为这将是一个有趣的现象,所以我尝试在代码中展示它 Thomas Weller提供了这段代码,当试图将一个较大的对象分配到LOH中释放的间隙中时,它似乎会导致OOM,但由于某种原因,它没有发生。 LOH是否在.net 4.6中自动压缩? 64位的LOH碎片化难道不是一个问题吗 资料来源: 类程序 { 静态IList small=新列表(); 静态IList big=新列表(); 静态void Ma

我正在为我的团队准备一个关于.NETGC和内存的演示。 不同来源讨论了碎片对大型对象堆的潜在影响。 因为这将是一个有趣的现象,所以我尝试在代码中展示它

Thomas Weller提供了这段代码,当试图将一个较大的对象分配到LOH中释放的间隙中时,它似乎会导致OOM,但由于某种原因,它没有发生。 LOH是否在.net 4.6中自动压缩? 64位的LOH碎片化难道不是一个问题吗

资料来源:

类程序
{
静态IList small=新列表();
静态IList big=新列表();
静态void Main()
{
int totalMB=0;
尝试
{
Console.WriteLine(“分配内存…”);
while(true)
{
添加(新字节[10*1024*1024]);
添加(新字节[85000-3*IntPtr.Size]);
总mb+=10;
WriteLine(“{0}MB已分配”,totalMB);
}
}
捕获(OutOfMemoryException)
{
WriteLine(“内存现在已满。如果愿意,请附加并调试。完成后按Enter键”);
WriteLine(“对于WinDbg,请尝试“!address-summary”和“!dumpheap-stat””;
Console.ReadLine();
大的,清楚的;
GC.Collect();
WriteLine(“大量内存已被释放。请使用相同的命令再次检查”);
Console.ReadLine();
尝试
{
添加(新字节[20*1024*1024]);
}
捕获(OutOfMemoryException)
{
WriteLine(“虽然{0}MB是空闲的,但无法分配20 MB。”,totalMB);
Console.ReadLine();
}
}
}
}
因为支持.NET 4.5.1(也是.NET Core)LOH压缩,并且行为可以通过静态类的
GCSettings.LargeObjectHeapCompactionMode
属性设置

这意味着,LOH由GC压实


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

我的猜测是,LOH不会自动压缩

因为紧凑型LOH会影响性能,所以我们应该在确定的情况下进行


有了这段代码,它很快就会耗尽内存,压缩操作只会回收没有引用的对象

谢谢!虽然据我所知,这种压缩必须在代码中设置,默认情况下不启用。因此,我仍然不理解为什么代码示例在释放大的块,然后尝试设置一个大于释放间隙的新块之后,不能导致OOM。资料来源:
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();
        }
    }
}
}