Mono 自動內存管理

https://blog.csdn.net/jinzhuojun/article/details/9292467

Mono在2.10版本之前集成BOEHM內存管理崖媚,2.11及更高版本使用SGen內存管理

Unity中Mono版本一直停留在2.10前栈幸。

1淳附、

1.1? ? ? BOEHM GC使用的是Mark-Sweep算法。

BOEHM GC基本步驟:

(1)標記階段:從根節(jié)點遍歷所有被引用的對象并標記蒙保;

(2)清除階段:將所有未標記對象內存釋放辕棚。

BOEHM GC是一種保守式的GC算法,只需要截斷原來的malloc()和free()接口替換為自己的GC_malloc()接口。

1.2? ? ?(以下所有計算均按64位操作系統(tǒng)處理)BOEHM內存分配根據內存大小分為小對象分配邏輯和大對象分配邏輯逝嚎,如果申請小于等于2048(2^12 / 2)字節(jié)則執(zhí)行小對象分配邏輯扁瓢,否則執(zhí)行大對象分配。小對象分配會包含三種內存分配:普通內存懈糯、指針內存涤妒、非回收內存。GC_obj_kinds數組用來區(qū)分三種不同類型的內存赚哗,所以該數組長度為3她紫。每一種類型都維護一個空閑內存鏈表數組ok_freelist,ok_freelist是一個長度為MAXOBJGRANULES(MAXOBJGRANULES為128)+1的數組屿储,每個數組元素指向一個空閑鏈表贿讹,該鏈表每一個元素指向一個大小為index*16的空閑內存塊。其中index為該鏈表所在數組的索引够掠,16為最小內存分配粒度民褂,128*16=2048即為小對象最大分配上限。

小對象內存分配疯潭,首先會查找GC_size_map表找到內存大小對應的內存分配索引赊堪。其中GC_size_map是一個長度為MAXOBJBYTES(MAXOBJBYTES為2048即最大分配內存上限)+1的數組,該數組的key代表申請內存大小竖哩,value即為內存分配索引哭廉。然后根據索引查找對應類型的GC_objfreelist,如果存在空閑內存塊則直接返回對應指針并將該內存塊從空閑鏈表移除相叁。否則執(zhí)行一次GC遵绰,如果GC后還沒有空閑列表則需要分配新的空閑內存塊,分配內存時增淹,首先根據申請內存大小通過公式(bytes+PAGE_SIZE-1)/PAGE_SIZE得到一個index椿访,從index開始遍歷GC_hblkfreelist數組,直到找到一個空閑塊虑润。(其中GC_hblkfreelist是一個類似于ok_freelist的數組成玫,長度為N_HBLK_FLS(N_HBLK_FLS為28)+1,每個元素也存儲一個空閑內存鏈表拳喻,每個鏈表元素指向一個PAGE_SIZE*index大小的內存塊梁剔,其中PAGE_SIZE為4096,index即為所在數組索引舞蔽。)然后將該空閑塊拆成一個PAGE塊和另一個塊,另一個塊放回GC_hblkfreelist中码撰,PAGE_SIZE塊根據申請大小拆成空閑塊列表返回給ok_freelist渗柿。

如果是大對象內存分配,直接查找GC_hblkfreelist分配一個內存塊。

每個PAGE塊分配時會生成一個HBLKHDR結構朵栖,該結構會記錄hb_sz颊亮、 hb_marks、descr等信息陨溅,其中h b_sz為拆分成ok_freelist塊的大小终惑,hb_marks標記拆分塊使用狀態(tài)。HBLKHDR結構用一個二維數組記錄门扇,每個HBLKHDR的存儲位置為[p>>22][p>>12 & 1024]雹有,其中P代表PAGE塊起始地址。HBLKHDR由非回收內存分配臼寄。

2霸奕、SGen(Simple Generational GC)是一種分代式垃圾回收器

SGen特點:

(1)分兩代:the nursery generation、the old generation吉拳;

(2)Stopiing the world:垃圾收集時质帅,所有運行線程需要停止;

(3)兩種主要收集方式:

minor collection:針對nursery generation留攒,采用copying collection煤惩;

major collection:針對the old generation,使用mark-sweep方式炼邀。

(4)Write barriers?

為了減少GC開銷魄揉,有時可能只需要進行nursery collection而不是完整的回收,但可能存在old generation中對象指向nursery中對象的情況:

這種情況就需要write barriers解決汤善,Mono中通過一個cardtables實現write barriers什猖。Cardtable會把major heap分為固定大小的塊(SGen中為512bytes)稱為card,每個card中有一個字節(jié)用來標記該card是否有對nursery中對象的引用红淡,如果有的話不狮,就會掃描該card中所有塊,找到引用的位于nursery中的對象進行標記Copy在旱。

(5)多線程

標記階段可以多個線程并行標記摇零,每一個線程包含一部分根對象,每一個線程有自己的gray stack,當多個線程同時遍歷到同一個引用對象時桶蝎,只有第一個找到該引用對象的線程才會將該對象壓入自己的gray stack進行后續(xù)處理驻仅。

2.1? ?minor collection和major collection:

(1)minor collection 主要針對nursery generation。步驟如下:

a登渣、識別并且標記 Pinned Objects

Pinned Object分為兩種:

第一種是使用fixed修飾符指定或者通過P/Invoke傳遞給非托管代碼使用的對象引用噪服,這種對象創(chuàng)建時就會標記為PINNED;

第二種就是通過保守式掃描棧和線程寄存器,找到可能引用的對象也標記為PINNED胜茧。

每個Mono Object創(chuàng)建時都會創(chuàng)建一個vtable指針粘优,vtable的低三位標記對象的狀態(tài)仇味,如圖2-1所示:

圖 2-1? vtable代表狀態(tài)

b、遍歷掃描所有roots找到所有引用雹顺,所有可達對象會被拷貝到the old generation并被標記為FORWARDED丹墨。整個過程使用一個gray stack實現,不斷將可達對象壓入棧中嬉愧,然后彈出棧中對象遍歷其引用對象再壓入棧贩挣,直到棧為空,所有引用對象處理完畢没酣。

圖2-2??
圖2-3??

c王财、清除未標記和非pinnded Object,如果是小對象會將空閑空間放到一個freelist供下次分配。

(2)major collection 主要針對the old generation四康,使用mark-sweep方式實現搪搏,標記階段和minor collection一樣,也是從root遍歷查找標記所有引用對象闪金,sweep階段會將未標記對象釋放疯溺,然后統(tǒng)計每個block中slot的占用率,如果指定slot大小的占用率低于設置的閾值時哎垦,會將該指定大小的slot順序拷貝到一個新分配的blocks中囱嫩,并將原slot置空等待下次回收并且重新構建free lists。

另外Mono對major collection的sweep階段進行了優(yōu)化即concurrent sweep漏设,sweep階段做的工作就是遍歷blocks墨闲,重置標記位,置空垃圾對象占用的slot以及重新構建free lists郑口,這些操作都不會影響minor collection鸳碧,所以minor collection可以和concurrent sweep并行進行。

2.2? ?內存分配

(1)小對象內存分配

Sgen初始化默認會分配一個4MB的連續(xù)空間作為nursery generation空間犬性,當小于等于8KB的對象申請空間時瞻离,會在the nursery generation中查找可用空間,如果已滿不足分配則會觸發(fā)minor collection乒裆。如果在多線程環(huán)境下套利,每個線程會分配一小塊nursery,Mono把它稱為TLABs(thread local allocation buffers)鹤耍,目前TLABs固定大小為4KB肉迫。

the old generation 會分配多個固定大小為16KB的Block,每個Block分割成等大小的slot稿黄,所有的slot記錄在一個free lists中便于分配喊衫。

(2)大于8KB的對象,Sgen會視為大對象杆怕,直接從操作系統(tǒng)申請內存空間族购,使用完后直接歸還給操作系統(tǒng)鼻听。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市联四,隨后出現的幾起案子,更是在濱河造成了極大的恐慌撑教,老刑警劉巖朝墩,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異伟姐,居然都是意外死亡收苏,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門愤兵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鹿霸,“玉大人,你說我怎么就攤上這事秆乳∨呈螅” “怎么了?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵屹堰,是天一觀的道長肛冶。 經常有香客問我,道長扯键,這世上最難降的妖魔是什么睦袖? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮荣刑,結果婚禮上馅笙,老公的妹妹穿的比我還像新娘。我一直安慰自己厉亏,他們只是感情好董习,可當我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著叶堆,像睡著了一般阱飘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上虱颗,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天沥匈,我揣著相機與錄音,去河邊找鬼忘渔。 笑死高帖,一個胖子當著我的面吹牛,可吹牛的內容都是我干的畦粮。 我是一名探鬼主播散址,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼乖阵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了预麸?” 一聲冷哼從身側響起瞪浸,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吏祸,沒想到半個月后对蒲,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡贡翘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年蹈矮,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸣驱。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡泛鸟,死狀恐怖,靈堂內的尸體忽然破棺而出踊东,到底是詐尸還是另有隱情北滥,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布递胧,位于F島的核電站碑韵,受9級特大地震影響,放射性物質發(fā)生泄漏缎脾。R本人自食惡果不足惜祝闻,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望遗菠。 院中可真熱鬧联喘,春花似錦、人聲如沸辙纬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽贺拣。三九已至蓖谢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間譬涡,已是汗流浹背闪幽。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留涡匀,地道東北人盯腌。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像陨瘩,于是被迫代替她去往敵國和親腕够。 傳聞我的和親對象是個殘疾皇子级乍,可洞房花燭夜當晚...
    茶點故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內容