當前位置:編程學習大全網 - 源碼下載 - Mono源碼閱讀-GC造成內存泄露問題

Mono源碼閱讀-GC造成內存泄露問題

本文主要記錄Mono源碼中會因為GC的問題,造成Unity遊戲不可避免的都會存在壹定得內存泄露問題的底層原因,涉及到Mono源碼中GC機制的邏輯。

要出現這種內存泄露,必須先準備壹塊任意的內存塊:(無任何外部引用,理論上應該會在用完後被GC,但在該BUG下會錯誤的泄露,不被GC掉)

NOTE:大小任意,越大越容易被泄露。

壹塊struct結構的數組:(struct內必須有壹個類似指針的值類型, 如int,和另壹個引用類型,如string)

NOTE:大小任意,數組內的元素越多越容易觸發泄露。例如 HashSet<String> 內部使用了該數據格式。

通過在GC中打點,和使用GDB調用GC過程,以便觀察所有對象的分配和GC的過程發現:buffer對象錯誤的被slots對象引用,導致buffer對象無法被正常GC,造成內存泄露。

首先對於mono/il2cpp的Boehm GC庫而言, mono/il2cpp的對象在分配內存的時候,會有幾種類型:

而在本例中:slots的分配是用NORMAL類型,buffer對象的分配是用PTRFREE類型。

因此在做GC的時候,對於slots對象,GC會掃描該對象的內存區間,查找其內部的指針地址,即從0xde45f000到0xde468c50地址按照指針對齊的方式查找指針地址:

例如:0xde45f000 0xde464d44 0xde464f40 0xde46513c ....

其中出現了 0xde464f40 這個地址的值剛好為:0xbe82f000(即Slot結構體內hashCode的值),而GC會錯誤的將該int型數值當做指針,而該指針剛好又指向了壹塊GC托管的內存塊,即buffer對象,因此GC認為該buffer對象被slots對象內部引用了,buffer對象也被GC標記,不會被釋放。

該問題的關鍵在於,GC將slot結構體內的hashcode這個int值錯誤的當做的指針,而該int值剛好又指向了另壹個托管的對象,因此GC錯認為了兩個對象存在引用關系,而造成內存泄露。

最小化Demo:

將struct Slot修改為class Slot,則可修復內存泄露問題,因為class對象的內存分配時TYPED類型。

因為Mono的GC的設計問題,Unity遊戲中幾乎不可避免的都會隨著時間出現內存泄露問題,因為例如HashSet這種數據結構內部都會出現該問題。但我們可以做的事情,依然是內存使用的兩大真理(特別是虛擬機類型的語言):

這樣做,不能完全避免Mono的底層GC問題,但是它可以讓這種內存泄露的變得更加平緩。

  • 上一篇:作為壹名計算機專業的學生,應該如何提高自己的編程水平?
  • 下一篇:投標匹配數量源代碼
  • copyright 2024編程學習大全網