我正在使用的C#/。NET應用程序正遭受緩慢的內存泄漏。我已經將CDB與SOS一起使用來嘗試確定正在發生的事情,但是數據似乎沒有任何意義,因此我希望你們中的一個以前可能已經經歷過這種情況。該應用程序在64位框架上運行。它正在不斷地計算數據并將其序列化到遠程主機,并且相當大地達到了大對象堆(LOH)。但是,我希望大多數LOH對象都是瞬態的:一旦計算完成并將其發送到遠程主機,就應該釋放內存。但是,我看到的是大量(活動的)對象數組與空閑的內存塊交錯,例如,從LOH中獲取隨機段:0:000> !DumpHeap 000000005b5b1000 000000006351da10 Address MT Size...000000005d4f92e0 0000064280c7c970 16147872000000005e45f880 00000000001661d0 1901752 Free000000005e62fd38 00000642788d8ba8 1056 <--000000005e630158 00000000001661d0 5988848 Free000000005ebe6348 00000642788d8ba8 1056000000005ebe6768 00000000001661d0 6481336 Free000000005f214d20 00000642788d8ba8 1056000000005f215140 00000000001661d0 7346016 Free000000005f9168a0 00000642788d8ba8 1056000000005f916cc0 00000000001661d0 7611648 Free00000000600591c0 00000642788d8ba8 105600000000600595e0 00000000001661d0 264808 Free...顯然,如果我的應用程序在每次計算過程中都創建了長壽命的大對象,我希望情況會如此。(這樣做是可以的,我接受會有一定程度的LOH碎片,但這不是問題所在。)問題是您在上述轉儲中看到的對象數組非常小(1056字節),我在代碼中看不到被創建,并以某種方式保持根源。還要注意,轉儲堆段時CDB不會報告類型:我不確定這是否相關。如果我轉儲標記的(<-)對象,CDB / SOS會很好地報告它:對象數組的元素都是字符串,從我們的應用程序代碼中可以識別出這些字符串。另外,由于!GCRoot命令掛起并且再也沒有回來,所以我找不到他們的GC根目錄(我什至試圖將其放置一夜)。因此,如果有人能解釋為什么這些小的(<85k)對象數組最終出現在LOH上,我將不勝感激:.NET在什么情況下會在其中放置一個小的對象數組?而且,有人碰巧知道確定這些對象根源的另一種方法嗎?更新1我昨天晚些時候提出的另一種理論是,這些對象數組起初很大,但是已經縮小了,留下了內存轉儲中明顯的可用內存塊。使我感到懷疑的是,對象數組總是看起來長1056字節(128個元素),引用的長度為128 * 8,開銷為32字節。想法是,庫中或CLR中的某些不安全代碼可能破壞了數組頭中元素數量的字段。我知道遠射...應用程序首先在循環中創建和取消引用唯一的字符串。這只是為了證明在這種情況下內存不會泄漏。顯然,它不應該也不應。在第二個循環中,創建并插入了唯一的字符串。此操作將它們根植在實習表中。我沒有意識到實習表是如何表示的??雌饋硭稍贚OH中創建的一組頁面(由128個字符串元素組成的對象數組)組成。這在CDB / SOS中更為明顯:請注意,對象數組的大小為528(而不是1056),因為我的工作站是32位,而應用程序服務器是64位。對象數組仍為128個元素長。因此,這個故事的寓意是要非常小心地進行實習。如果未知您正在實習的字符串是有限集的成員,則您的應用程序將因LOH的碎片而泄漏,至少在CLR版本2中會這樣。在我們的應用程序的情況下,反序列化代碼路徑中存在通用代碼,可在解組期間實習實體標識符:我現在強烈懷疑這是罪魁禍首。但是,開發人員的意圖顯然是好的,因為他們想確保如果對同一實體進行多次反序列化,則只有一個標識符字符串實例將保留在內存中。
4 回答

富國滬深
TA貢獻1790條經驗 獲得超9個贊
在閱讀有關GC如何工作的描述以及關于壽命長的對象如何在第二代中結束的部分以及LOH對象的收集僅在完全收集時發生-與第二代的收集一樣,這個想法浮現在腦海。 ..為什么不將第二代和大型對象放在同一堆中,因為它們將被收集在一起?
如果這是實際發生的情況,那么它將解釋小物體如何最終與LOH并存-如果它們的壽命足夠長,可以在第二代中終結。
因此,您的問題似乎很好地反駁了我的想法-這將導致LOH分散。
摘要:你的問題可以通過蕙解釋和第2代共享同一個堆區,盡管這絕不是證明,這樣的解釋。
更新:!dumpheap -stat
幾乎所有的輸出使這一理論無所作為!第二代和LOH有自己的區域。

慕運維8079593
TA貢獻1876條經驗 獲得超5個贊
很好的問題,我通過閱讀問題中學到了。
我認為反序列化代碼路徑的其他部分也正在使用大對象堆,因此會產生碎片。如果所有琴弦都在同一時間被扣押,我想你會沒事的。
鑒于.net垃圾收集器的性能如何,僅讓反序列化代碼路徑創建普通的字符串對象就足夠了。在需求得到證實之前,不要做任何更復雜的事情。
我最多只能看看保留您所看到的最后幾個字符串的哈希表,然后再使用它們。通過限制哈希表的大小并在創建表時傳遞該大小,可以停止大多數碎片。然后,您需要一種方法,從哈希表中刪除您最近未看到的字符串,以限制其大小。 但是,如果反序列化代碼路徑創建的字符串壽命很短,那么您將不會獲得太多收益。
- 4 回答
- 0 關注
- 558 瀏覽
添加回答
舉報
0/150
提交
取消