Gis*_*shu 8 .net c# garbage-collection
在与同事谈论启动时使用近1.5G内存的特定应用程序组时...他指出了一个关于.NET生产调试的非常好的链接
困惑的部分是......
例如,如果为单个块分配1 MB内存,则大对象堆的大小将扩展为1 MB.释放此对象时,大对象堆不会解除对虚拟内存的响应,因此堆的大小保持为1 MB.如果稍后再分配另一个500 KB块,则新块将在属于大对象堆的1 MB内存块中分配.在进程生命周期中,大对象堆总是增长以保存当前引用的所有大块分配,但是在释放对象时从不收缩,即使发生了垃圾收集.下一页的图2.4显示了一个大对象堆的示例.
现在让我们假设我们有一个虚构的应用程序,可以创建一大堆大对象(> 85KB),所以大对象堆增长让我们说200兆.现在假设我们有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<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
}
Run Code Online (Sandbox Code Playgroud)
我想首先澄清一下. - 假设您正在运行应用程序作为32位应用程序,您的进程可用的VA空间仅为2 GB,如果您启用了大地址空间切换,则为3 GB,因此即使您有巨大的页面文件,如果您是32位也没关系过程,如果您运行64位,那么您将拥有巨大的地址空间.
所以你会在其中一个案例中找回记忆.您在达到2GB限制之前达到OOM的事实可能意味着您有VA碎片,当您没有连续的VA地址空间来满足新的分配时会发生VA碎片,例如您要求8KB段,并且您不要你的VA连续2页(假设页面大小为4 K)
您可以在Windows的调试工具中使用!vamap调试器扩展来验证这一点.
希望这有助于谢谢