Csharp/C#教程:如何从多个托管应用程序的大对象堆LOH中取回未使用的内存?分享


如何从多个托管应用程序的大对象堆LOH中取回未使用的内存?

在与同事谈论启动时使用近1.5G内存的特定应用程序组时…他指出了一个关于.NET生产调试的非常好的链接

困惑的部分是……

例如,如果为单个块分配1 MB内存,则大对象堆的大小​​将扩展为1 MB。 释放此对象时,大对象堆不会解除对虚拟内存的影响,因此堆的大小保持为1 MB。 如果稍后再分配另一个500 KB块,则新块将在属于大对象堆的1 MB内存块中分配。 在进程生命周期中,大对象堆总是增长以保存当前引用的所有大块分配,但是在释放对象时从不收缩,即使发生了垃圾收集。 下一页的图2.4显示了一个大对象堆的示例。

现在让我们假设我们有一个虚构的应用程序,可以创建一大堆大对象(> 85KB),所以大对象堆增长让我们说200 Meg。 现在假设我们有10个这样的app实例正在运行..所以分配了2000 Megs。 现在这个记忆永远不会回到操作系统,直到过程关闭……(就是我所理解的)

我的理解是否有任何差距? 我们如何在各种LOHeaps中找回未使用的内存; 我们不创造OutOfMemoryExceptions的完美风暴?

更新:从Marc的回复中,我想澄清LOH对象没有被引用 – 大对象是use-n-throw – 但是即使堆在初始激增之后堆相对空,堆也不会收缩。

更新#2:只是包含一个代码片段(夸大但我觉得有点了)..我看到一个OutOfMemoryException,虚拟内存在我的机器上达到1.5G标记(1.7G在另一个上)…来自Eric L 。博客文章 ,’进程内存可以被视为磁盘上的大量文件……’ – 因此这个结果是出乎意料的。 在这种情况下,机器在HDD上具有GB的可用空间。 PageFile.sys OS文件(或相关设置)是否施加了任何限制?

static float _megaBytes; static readonly int BYTES_IN_MB = 1024*1024; static void BigBite() { try { var list = new List(); int i = 1; for (int x = 0; x < 1500; x++) { var memory = new byte[BYTES_IN_MB + i]; _megaBytes += memory.Length / BYTES_IN_MB; list.Add(memory); Console.WriteLine("Allocation #{0} : {1}MB now", i++, _megaBytes); } } catch (Exception e) { Console.WriteLine("Boom! {0}", e); // I put a breakpoint here to check the console throw; } } static void Main(string[] args) { BigBite(); Console.WriteLine("Check VM now!"); Console.ReadLine(); _megaBytes = 0; ThreadPool.QueueUserWorkItem(delegate { BigBite(); }); ThreadPool.QueueUserWorkItem(delegate { BigBite(); }); Console.ReadLine(); // will blow before it reaches here } 

我想首先澄清一下。 – 假设您正在运行应用程序作为32位应用程序,您的进程可用的VA空间仅为2 GB,如果您启用了大型地址空间交换机,则为3 GB,因此即使您有巨大的页面文件,如果您是32位也没关系过程,如果你运行64位,你有很大的地址空间,这很重要。

所以你会在其中一个案例中找回记忆。 你在达到2GB限制之前击中OOM的事实可能意味着你有VA碎片,当你没有连续的VA地址空间来满足新的分配时会发生VA碎片,例如你要求8KB的段,你不要你的VA连续2页(假设页面大小为4 K)

您可以在Windows的调试工具中使用!vamap调试器扩展来validation这一点。

希望这有助于谢谢

如果LOH想要保留内存,那就是LOH – 但是,不要忘记OutOfMemoryException是按进程进行的,因为硬盘确实是虚拟内存的限制因素。 Eric Lippert最近在博客上发表了这篇文章 。 当然,这并不妨碍它从所有分页中获得糟糕的性能……

好吧,如果你真的有这种分配模式,你可以将你的大对象移动到另一个appdomain – 当你决定释放所有大对象时,释放appdomain并释放该appdomain的堆。

上述就是C#学习教程:如何从多个托管应用程序的大对象堆LOH中取回未使用的内存?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/cdevelopment/1003612.html

(0)
上一篇 2021年12月28日
下一篇 2021年12月28日

精彩推荐