在談到關於採用了在啓動時近1.5G內存的應用程序的特定組的同事......他向我指出一個非常好的鏈接.NET production debugging如何從多個託管應用程序的大對象堆LOH中獲取未使用的內存?
有我疑惑的是該部分...
例如,如果您將1 MB的 內存分配給單個塊,則大對象堆將擴展爲1 MB大小。 釋放此對象時,大型對象堆 不會解除虛擬內存的 解析,因此堆保持大小爲1 MB。如果您稍後分配了另一個 500 KB塊,則新塊將在 內存的1 MB塊內分配的 屬於大對象 堆。在過程生命週期中,大對象堆始終增長爲保留 當前引用的所有大塊分配 ,但從未 在釋放對象時收縮,即使發生垃圾回收也不會收縮 。 下一頁的圖2.4顯示了一個大對象堆的示例 。
現在我們假設我們有一個虛構的應用程序,它會創建一系列大對象(大於85KB),所以大對象堆增長可以說爲200兆。現在讓我們說,我們有10個這樣的應用程序實例正在運行..以便分配2000個Megs。現在是這個內存永遠不會回到操作系統,直到過程關閉...(是我所理解的)
我的理解有沒有差距?我們如何在各種LOHeap中找回未使用的記憶;我們不會創建OutOfMemoryExceptions的完美風暴嗎?
更新:從Marc的迴應中,我想澄清一下,LOH對象沒有被引用 - 大對象是use-n-throw - 但是即使堆相對空初始激增。
更新#2:就包括代碼段(誇張,但得到的點對面,我認爲)。我看到身邊的時候,一個OutOfMemoryException虛擬內存擊中1.5G標記我的機器(1.7G上另一)..從Eric L.'s blog post,'進程內存可視化爲磁盤上的海量文件..' - 這個結果是意料之外的。在這種情況下,機器在硬盤上有可用空間的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
}
(回覆評論) – 2009-06-24 10:11:58