蕙碎片 - 2015年更新蕙碎片 - 2015年更新(LOH fragmentation - 2

2019-05-12 07:03发布

有可用的很多信息有关.NET LOH,它已在各种文章中说明。 然而,似乎有些文章缺乏一点精度。

过时的信息

在布莱恩·拉斯穆森的回答(2009年),项目经理在微软 ,他说,限制为85000个字节。 他还让我们知道我们有一个更奇怪的情况下double[]的尺寸1000个的元素。 同样的85000限制由规定的猫腻斯蒂芬斯(MSDN,2008年),在CLR团队的一员 。

在评论,布莱恩·拉斯穆森变得更加准确,让我们知道,它可以与再现byte[]的85000个字节- 12个字节。

2013更新

马里奥·赫沃特(“高级Windows调试”的作者)告诉我们,在2013年的。NET 4.5.1现在可以压缩LOH为好,如果我们告诉它这样做。 因为它是默认关闭的,问题依然存在,除非你意识到这一点了。

2015年更新

我不能再现byte[]例如任何更多。 具有短的蛮力算法,我发现我必须减去24代替( byte[84999-24]在SOH, byte[85000-24]在LOH):

    static void Main(string[] args)
    {
        int diff = 0;
        int generation = 3;
        while (generation > 0)
        {
            diff++;
            byte[] large = new byte[85000-diff];
            generation = GC.GetGeneration(large);
        }            
        Console.WriteLine(diff);
    }

我也无法重现的double[]声明。 暴力破解给了我10622元为界( double[10621]在SOH, double[10622]在LOH):

    static void Main(string[] args)
    {
        int size = 85000;
        int step = 85000/2;
        while (step>0)
        {
            double[] d = new double[size];
            int generation = GC.GetGeneration(d);
            size += (generation>0)?-step:step;
            step /= 2;
        }
        Console.WriteLine(size);
    }

出现这种情况,即使我编译应用程序为老年.NET框架。 它也并不依赖于发行或调试版本。

如何在变化来解释?

Answer 1:

从12至24中的变化byte[]例如可通过在CPU架构从32到64位的变化来解释。 在编译为64或AnyCPU方案,从2×4字节的.NET开销增加(4个字节对象头+ 4个字节方法表)至2 * 8个字节(8个字节对象头+ 8个字节方法表)。 此外,该阵列具有4个字节(32位)对8个字节(64位)的长度属性。

对于double[]例如,只要使用一个计算器:85000个字节/ 64位的双类型= 10625项,这已经是接近。 考虑到.NET开销,结果是(85000个字节 - 24个字节)每双= 10622双打/ 8个字节。 因此,有没有特殊的处理double[]了。

顺便说一句,我从来没有发现LOH不成任何工作前示威,所以我写了一个自己。 只是编译的x86下面的代码并运行它。 它甚至还包括一些调试提示。

当作为64位编译自Windows可能会增加页面文件的大小,它不会工作为好,这样的20 MB内存的后续分配能够成功一次。

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();
            }
        }
    }
}


文章来源: LOH fragmentation - 2015 update