LOH 碎片 - 2015 年更新

2024-03-29

有大量有关 .NET LOH 的信息,并且已在各种文章中进行了解释。不过,有些文章似乎缺乏一点精确性。

过时的信息

In Brian Rasmussen 的回答 (2009),Microsoft 项目经理 https://stackoverflow.com/a/687155/480982,他说限制是 85000 字节。他还让我们知道还有一个更奇怪的案例double[]大小为 1000 个元素。同样的 85000 限制由Maoni Stephens(MSDN,2008),CLR 团队成员 https://msdn.microsoft.com/en-us/magazine/cc534993.aspx.

在评论中,Brian Rasmussen 变得更加准确,让我们知道它可以用byte[]85000 字节 - 12 字节。

2013年更新

Mario Hewardt(《高级 Windows 调试》作者) http://blogs.msdn.com/b/mariohewardt/archive/2013/06/26/no-more-memory-fragmentation-on-the-large-object-heap.aspx2013 年告诉我们,.NET 4.5.1 现在也可以压缩 LOH,如果我们告诉它这样做的话。由于默认情况下它是关闭的,因此问题仍然存在,除非您已经意识到这一点。

2015年更新

我无法重现byte[]再举个例子吧。通过一个简短的强力算法,我发现我必须减去 24 (byte[84999-24]在苏俄,byte[85000-24]在洛):

    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]在苏俄,double[10622]在洛):

    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 框架编译应用程序,也会发生这种情况。它也不依赖于发布或调试版本。

如何解释这些变化?


从 12 到 24 的变化byte[]这个例子可以通过 CPU 架构从 32 位到 64 位的变化来解释。在为 x64 或 AnyCPU 编译的程序中,.NET 开销从 2*4 字节(4 字节对象头 + 4 字节方法表)增加到 2*8 字节(8 字节对象头 + 8 字节方法表)。此外,该数组的长度属性为 4 字节(32 位)与 8 字节(64 位)。

For the double[]例如,只需使用计算器:double 类型的 85000 字节/64 位 = 10625 项,这已经很接近了。考虑到 .NET 开销,结果为(85000 字节 - 24 字节)/每个双精度数 8 字节 = 10622 双精度数。所以没有特殊处理double[]不再有。

顺便说一句,我以前从未找到过任何 LOH 碎片的有效演示,所以我自己写了一个。只需为 x86 编译以下代码并运行即可。它甚至包括一些调试提示。

当编译为 x64 时,它不会正常工作,因为 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();
            }
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LOH 碎片 - 2015 年更新 的相关文章

  • 检查仪器中的内存分配

    我已经使用泄漏工具清除了应用程序的泄漏 但我仍然注意到当我切换视图时 objectalloc 工具分配的对象数量和占用空间会增加 我特别看到大量 GeneralBlock 16 主要由基金会负责调用者 NSLogv and GeneralB
  • 如何在 Google 日历中创建“recurData”?

    我想使用 Google API 创建日历的重复事件 我正在关注链接 谷歌日历API http code google com apis calendar data 2 0 developers guide dotnet html Creat
  • C# 检查闰年

    我想将输入日期 1 年添加到名为完成日期的列中 如果输入日期是闰年 我需要添加 364 天 如果不是 365 天的话 有没有办法在 c 中检查这一点 使用当前日期时间年份并操作闰年 不操作 然后添加天数 Thanks 您可以使用日期时间 I
  • 从 C 调用带有字符串参数的 Go 函数?

    我可以从 C 调用一个没有参数的 Go 函数 按照下面的 https github com joeprivacy crefgo hello world 这通过编译go build和打印 Hello from Golang main func
  • M1 MacBook Pro 和 cmake 的编译错误

    我刚刚拿到了新的 M1 MacBook Pro 正在尝试编译大学工作所需的代码库 以下是我已采取的步骤 我使用 Rosetta 将终端设置为始终打开 安装的自制程序using bin bash c curl fsSL https raw g
  • 使用 JsonWriter 时,WriteStartConstructor 的用途是什么?

    标题说明了一切 我看到它 及其相应的结尾 吐出以下内容 new Foo 但我不明白什么new实际上是在反序列化时执行的 文档只是说它编写了一个 Json 构造函数 但没有说 Json 构造函数是什么is 此方法是作为增强功能的一部分引入的
  • Task.WaitAll 保持循环

    我正在尝试这个异步代码只是为了测试 async 关键字 public async Task
  • 不明确的元函数或未定义的类型

    我是元功能的新手 我想编写一个函数 将复合类型中某种类型的所有匹配项替换为其他类型 在示例中 replace
  • 为 C# 和 C++ 应用程序编写 DLL

    我需要编写几个 DLL 它们都可以从 C 应用程序和 C 应用程序访问 最初 我认为通过用 C 编写 DLL 并从 C 和 C 应用程序链接到它们可以节省时间 精力 这种方法明智吗 还是应该使用 C 编写 DLL 我的建议是在您最舒服的地方
  • 移动数组中的元素

    我需要一点帮助 我想将数组中的元素向上移动一个元素 以便新位置 1 包含位置 1 中的旧值 new 2 包含 old 1 依此类推 旧的最后一个值被丢弃 第一个位置的新值是我每秒给出的新值 我使用大小为 10 的数组 uint32 t TE
  • IBM Rhapsody 中状态图终止连接器的理解

    在IBM Rhapsody中 如果我使用new创建了一个类的实例 那么我们是否必须通过调用delete来处理内存的释放 或者Termination Connector将在其状态图中通过内存释放来处理其销毁 如果您使用 C 和 OXF 对象执
  • 如何从与桌面交互的应用程序与 Windows 服务进行通信?

    使用 Net 与服务交互的最佳方式是什么 即大多数托盘应用程序如何与其服务器通信 如果这个方法也是跨平台的 那就更好了 在 Mono 中工作 所以我猜远程处理已经过时了 Edit 忘了说了 我们仍然需要在现场支持 Windows 2000
  • 缓冲区溢出(与)缓冲区溢出(与)堆栈溢出[重复]

    这个问题在这里已经有答案了 可能的重复 堆栈溢出和缓冲区溢出有什么区别 https stackoverflow com questions 1120575 what is the difference between a stack ove
  • 何时使用 const char * 何时使用 const char[]

    我知道它们是不同的 我知道它们有何不同 并且我阅读了我能找到的所有关于char vs char 但所有这些答案都没有告诉我们什么时候应该使用它们 所以我的问题是 你什么时候使用 const char text text 你什么时候使用 co
  • 位运算符,而不是在分支中使用异或

    问完后这个问题 https stackoverflow com questions 22336015 why use xor with a literal instead of inversion bitwise not 我收到了 Ando
  • 如何在 if () 语句中声明变量? [复制]

    这个问题在这里已经有答案了 可能的重复 在 C 的条件或控制语句中声明和初始化变量 https stackoverflow com questions 1516919 declaring and initializing a variabl
  • 引用计数类和多线程

    我是多线程编程的新手 对此我仍然感到困惑 下面是我的引用计数类 class Rbuffer private char m pnData volatile unsigned int mRefCount public Rbuffer int n
  • ASP.Net Core 中没有智能感知

    通过 Visual Studio 安装 ASP Net Core gt 新项目 gt Web gt ASP Net Web 应用程序 gt 确定 gt ASP Net 5 模板 安装后重新启动系统 然后创建一个新项目ASP NET 5 Te
  • Security.h 中结构的 macOS 文档

    我正在尝试使用Security h通过 Java 和 JNA 的 macOS 框架 这意味着我需要将某些结构重建为 Java 类 问题是 当我查看文档中的结构时 this one https developer apple com refe
  • 为什么 typeof 函数在 C 中不起作用

    我使用GCC编译器 版本9 2 0 我想在 C 中使用 typeof 函数 但它会引发错误 错误 typeof 之前的预期表达式 如果您需要更多信息 请询问我 int a 5 double b the expected result is

随机推荐