我有一個類,它有一個字節數組從1,048,576字節持有到134,217,728字節。 在處置void中,我將數組設置爲null,之後調用dispose的方法調用GC.Collect
。C#大字節數組和內存泄漏如果不迅速消失
如果我立即處置,我會回憶我的記憶,但如果我等待10小時並處置,內存使用情況不會改變。
我有一個類,它有一個字節數組從1,048,576字節持有到134,217,728字節。 在處置void中,我將數組設置爲null,之後調用dispose的方法調用GC.Collect
。C#大字節數組和內存泄漏如果不迅速消失
如果我立即處置,我會回憶我的記憶,但如果我等待10小時並處置,內存使用情況不會改變。
內存使用量基於操作系統內存分配。它可能立即被釋放,可能不會。這取決於操作系統的利用率,應用程序等。你可以在運行時釋放它,但這並不意味着操作系統總是能夠恢復它。我必須考慮基於記憶模式(即時間)的決定,它會影響計算何時歸還或不歸屬。這是在這裏解決:
注:如果內存沒有被釋放,它不會自動意味着它使用。無論是否釋放內存大小,都取決於CLR,但是這種內存不會被浪費。
也就是說,如果你想有一個技術性的解釋,你需要閱讀litterature對大對象堆:http://msdn.microsoft.com/en-us/magazine/cc534993.aspx
基本上,它是其中非常大的對象(超過85KB以上)的分配的內存區。它不同於其他記憶區域,因爲它從來沒有壓縮過,因此可能變得碎片化。我想你的情況會發生什麼:
情況1:你分配對象並立即調用GC.Collect。該對象分配在堆的末尾,然後釋放。 CLR在堆的末尾看到一個空閒段並將其釋放到操作系統。案例2:你分配對象並等待一段時間。與此同時,另一個對象被分配到LOH中。現在,你的對象不再是最後一個了。然後,當你調用GC.Collect時,你的對象被擦除,但內存段末尾還有其他對象。所以CLR不能將內存釋放到操作系統。
只是基於我在.NET中的內存管理知識的猜測。我可能完全錯誤。
您的發現並不罕見,但這並不意味着任何錯誤。爲了收集,一些東西必須提示GC收集(通常是嘗試分配)。因此,您可以構建一個消耗大量內存的應用程序,釋放它,然後閒置。如果機器上沒有內存壓力,並且如果您的應用程序在此之後不嘗試做任何事情,則GC不會啓動(因爲它不需要)。一旦你忙,GC就會開始工作。這種行爲通常被誤認爲泄漏。
答案: 您是否多次使用這個非常大的陣列?如果是這樣,你最好將它放在周圍並重新使用它。原因:在大對象堆上分配大於85,000字節的任何對象。該堆只在第二代集合中獲得GC'd。所以如果你經常分配和重新分配數組,你將會導致很多Gen 2(昂貴的)集合。 (注意:這並不意味着總是重用大型數組有一條硬性規則,但如果你正在做大量的數組分配/釋放/分配,你應該測量它有多大的幫助你重新使用)。
實際上,我使包含不同大小數組的類的實例,隨機任何人都可以被處置。 – jasonbay13
我明白了。如果你想真正測試一個泄漏是否發生,你可以拋出一些測試代碼,只是不斷創建和釋放這些數組。他們最終會消失。可能發生的情況是系統沒有足夠的壓力來提示第二代系列。或者,也可能是Adam Tuliper說的 - 數組正在被釋放,但內存不會立即回到O/S。無論哪種方式,只要你不在某個地方持有對數組的引用,它可能不是真正的泄漏。 – JMarsch
到目前爲止好。你的問題是什麼? –
我不明白爲什麼時間會導致內存不能被釋放。以及是否有解決問題的辦法。 – jasonbay13
@ jasonbay13:當內存被使用了很長時間後,它被推廣到垃圾收集的世代。當它處於後代時,它往往不會被收集到系統需要它,它本身不是泄漏。您是否嘗試過'GC.Collect'上的'Force'選項並指定要收集的世代? –