gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 18:28:27 25 4
gpt4 key购买 nike

在与一位同事谈论一组特定的应用程序在启动时使用近 1.5G 内存时...他向我指出了一个很好的链接 .NET production debugging

让我困惑的部分是......

For example, if you allocate 1 MB of memory to a single block, the large object heap expands to 1 MB in size. When you free this object, the large object heap does not decommit the virtual memory, so the heap stays at 1 MB in size. If you allocate another 500-KB block later, the new block is allocated within the 1 MB block of memory belonging to the large object heap. During the process lifetime, the large object heap always grows to hold all the large block allocations currently referenced, but never shrinks when objects are released, even if a garbage collection occurs. Figure 2.4 on the next page shows an example of a large object heap.

现在假设我们有一个虚构的应用程序,它创建了一系列大对象 (> 85KB),所以大对象堆增长到 200 兆。现在假设我们有 10 个这样的应用程序实例正在运行......因此分配了 2000 Megs。现在是不是在进程关闭之前,这个内存永远不会返回给操作系统......(这是我的理解)

我的理解有没有漏洞?我们如何取回各种 LOHeaps 中未使用的内存;我们不会制造 OutOfMemoryExceptions 的完美 Storm ?

更新:根据 Marc 的回复,我想澄清的是 LOH 对象未被引用 - 大对象是 use-n-throw - 然而即使堆是初始激增后相对空旷。

更新 #2: 只包括一个代码片段(夸张但我认为明白了要点)。我在我的机器上虚拟内存达到 1.5G 标记时看到了 OutOfMemoryException(另一个1.7G)..来自Eric L.'s blog post ,“进程内存可以可视化为磁盘上的一个大文件..”——因此这个结果是出乎意料的。本例中的机器在 HDD 上有 GB 的可用空间。 PageFile.sys 操作系统文件(或相关设置)是否有任何限制?

        static float _megaBytes;
static readonly int BYTES_IN_MB = 1024*1024;

static void BigBite()
{
try
{
var list = new List<byte[]>();
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,如果启用大地址空间开关则为 3GB,因此即使您有巨大的页面文件,如果您是 32 位的也没关系进程,如果你运行 64 位,这很重要,你有巨大的地址空间。

  • 大小 > 85000 字节 的对象分配在 LOH 上,请注意它是 85000 字节 而不是 85K,这也是可能更改的实现细节。现在,回到你的问题。GC 将取消提交在 2 种情况下未使用的 LOH 段1- 当机器上的内存压力很高时 (~95-98%)2- 当它不能满足新的分配请求时,它将取消提交 LOH 中未使用的页面

因此,在其中一种情况下,您将取回内存。在达到 2GB 限制之前遇到 OOM 的事实可能意味着您有 VA 碎片,当您没有连续的 VA 地址空间来满足新分配时,就会发生 VA 碎片,例如您要求 8KB 段,而您没有您的 VA 中没有 2 个连续的页面(假设页面大小为 4 K)

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

希望对你有帮助谢谢

关于c# - 如何从多个托管应用程序的大对象堆 LOH 中取回未使用的内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1037344/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com