GC的前世與今生
雖然本文是以.NET作為目標來講述GC,但是GC的概念并非才誕生不久。早在1958年,由鼎鼎大名的圖林獎得主John McCarthy所實現的Lisp語言就已經提供了GC的功能,這是GC的第一次出現。Lisp的程序員認為內存管理太重要了,所以不能由程序員自己來管理。但后來的日子里Lisp卻沒有成氣候,采用內存手動管理的語言占據了上風,以C為代表。出于同樣的理由,不同的人卻又不同的看法,C程序員認為內存管理太重要了,所以不能由系統來管理,并且譏笑Lisp程序慢如烏龜的運行速度。的確,在那個對每一個Byte都要精心計算的年代GC的速度和對系統資源的大量占用使很多人的無法接受。而后,1984年由Dave Ungar開發的Small talk語言第一次采用了Generational garbage collection的技術(這個技術在下文中會談到),但是Small talk也沒有得到十分廣泛的應用。
直到20世紀90年代中期GC才以主角的身份登上了歷史的舞臺,這不得不歸功于Java的進步,今日的GC已非吳下阿蒙。Java采用VM(Virtual Machine)機制,由VM來管理程序的運行當然也包括對GC管理。90年代末期.NET出現了,.NET采用了和Java類似的方法由CLR(Common Language Runtime)來管理。這兩大陣營的出現將人們引入了以虛擬平臺為基礎的開發時代,GC也在這個時候越來越得到大眾的關注。
為什么要使用GC呢?也可以說是為什么要使用內存自動管理?有下面的幾個原因:
1、提高了軟件開發的抽象度;
2、程序員可以將精力集中在實際的問題上而不用分心來管理內存的問題;
3、可以使模塊的接口更加的清晰,減小模塊間的偶合;
4、大大減少了內存人為管理不當所帶來的Bug;
5、使內存管理更加高效。
總的說來就是GC可以使程序員可以從復雜的內存問題中擺脫出來,從而提高了軟件開發的速度、質量和安全性。
什么是GC
GC如其名,就是垃圾收集,當然這里僅就內存而言。Garbage Collector(垃圾收集器,在不至于混淆的情況下也成為GC)以應用程序的root為基礎,遍歷應用程序在Heap上動態分配的所有對象[2],通過識別它們是否被引用來確定哪些對象是已經死亡的哪些仍需要被使用。已經不再被應用程序的root或者別的對象所引用的對象就是已經死亡的對象,即所謂的垃圾,需要被回收。這就是GC工作的原理。為了實現這個原理,GC有多種算法。比較常見的算法有Reference Counting,Mark Sweep,Copy Collection等等。目前主流的虛擬系統.net CLR,Java VM和Rotor都是采用的Mark Sweep算法。
一、Mark-Compact 標記壓縮算法 簡單把.NET的GC算法看作Mark-Compact算法
階段1: Mark-Sweep 標記清除階段
先假設heap中所有對象都可以回收,然后找出不能回收的對象,給這些對象打上標記,最后heap中沒有打標記的對象都是可以被回收的
階段2: Compact 壓縮階段
對象回收之后heap內存空間變得不連續,在heap中移動這些對象,使他們重新從heap基地址開始連續排列,類似于磁盤空間的碎片整理
Heap內存經過回收、壓縮之后,可以繼續采用前面的heap內存分配方法,即僅用一個指針記錄heap分配的起始地址就可以
主要處理步驟:將線程掛起=>確定roots=>創建reachable objectsgraph=>對象回收=>heap壓縮=>指針修復
可以這樣理解roots:heap中對象的引用關系錯綜復雜(交叉引用、循環引用),形成復雜的graph,roots是CLR在heap之外可以找到的各種入口點。GC搜索roots的地方包括全局對象、靜態變量、局部對象、函數調用參數、當前CPU寄存器中的對象指針(還有finalizationqueue)等。主要可以歸為2種類型:已經初始化了的靜態變量、線程仍在使用的對象(stack+CPU register)
Reachable objects:指根據對象引用關系,從roots出發可以到達的對象。例如當前執行函數的局部變量對象A是一個rootobject,他的成員變量引用了對象B,則B是一個reachable object。從roots出發可以創建reachable objectsgraph,剩余對象即為unreachable,可以被回收
指針修復是因為compact過程移動了heap對象,對象地址發生變化,需要修復所有引用指針,包括stack、CPUregister中的指針以及heap中其他對象的引用指針
Debug和release執行模式之間稍有區別,release模式下后續代碼沒有引用的對象是unreachable的,而debug模式下需要等到當前函數執行完畢,這些對象才會成為unreachable,目的是為了調試時跟蹤局部對象的內容
傳給了COM+的托管對象也會成為root,并且具有一個引用計數器以兼容COM+的內存管理機制,引用計數器為0時這些對象才可能成為被回收對象
Pinnedobjects指分配之后不能移動位置的對象,例如傳遞給非托管代碼的對象(或者使用了fixed關鍵字),GC在指針修復時無法修改非托管代碼中的引用指針,因此將這些對象移動將發生異常。pinnedobjects會導致heap出現碎片,但大部分情況來說傳給非托管代碼的對象應當在GC時能夠被回收掉
二、 Generational 分代算法 程序可能使用幾百M、幾G的內存,對這樣的內存區域進行GC操作成本很高,分代算法具備一定統計學基礎,對GC的性能改善效果比較明顯
將對象按照生命周期分成新的、老的,根據統計分布規律所反映的結果,可以對新、老區域采用不同的回收策略和算法,加強對新區域的回收處理力度,爭取在較短時間間隔、較小的內存區域內,以較低成本將執行路徑上大量新近拋棄不再使用的局部對象及時回收掉
分代算法的假設前提條件:
1、大量新創建的對象生命周期都比較短,而較老的對象生命周期會更長
2、對部分內存進行回收比基于全部內存的回收操作要快
3、新創建的對象之間關聯程度通常較強。heap分配的對象是連續的,關聯度較強有利于提高CPU cache的命中率
.NET將heap分成3個代齡區域: Gen 0、Gen 1、Gen 2
Heap分為3個代齡區域,相應的GC有3種方式: # Gen 0 collections, # Gen 1 collections, #Gen 2 collections。如果Gen 0 heap內存達到閥值,則觸發0代GC,0代GC后Gen 0中幸存的對象進入Gen1。如果Gen 1的內存達到閥值,則進行1代GC,1代GC將Gen 0 heap和Gen 1 heap一起進行回收,幸存的對象進入Gen2。2代GC將Gen 0 heap、Gen 1 heap和Gen 2 heap一起回收
Gen 0和Gen 1比較小,這兩個代齡加起來總是保持在16M左右;Gen2的大小由應用程序確定,可能達到幾G,因此0代和1代GC的成本非常低,2代GC稱為fullGC,通常成本很高。粗略的計算0代和1代GC應當能在幾毫秒到幾十毫秒之間完成,Gen 2 heap比較大時fullGC可能需要花費幾秒時間。大致上來講.NET應用運行期間2代、1代和0代GC的頻率應當大致為1:10:100。
三、Finalization Queue和Freachable Queue
這兩個隊列和.net對象所提供的Finalize方法有關。這兩個隊列并不用于存儲真正的對象,而是存儲一組指向對象的指針。當程序中使用了new操作符在Managed Heap上分配空間時,GC會對其進行分析,如果該對象含有Finalize方法則在Finalization Queue中添加一個指向該對象的指針。在GC被啟動以后,經過Mark階段分辨出哪些是垃圾。再在垃圾中搜索,如果發現垃圾中有被Finalization Queue中的指針所指向的對象,則將這個對象從垃圾中分離出來,并將指向它的指針移動到Freachable Queue中。這個過程被稱為是對象的復生(Resurrection),本來死去的對象就這樣被救活了。為什么要救活它呢?因為這個對象的Finalize方法還沒有被執行,所以不能讓它死去。Freachable Queue平時不做什么事,但是一旦里面被添加了指針之后,它就會去觸發所指對象的Finalize方法執行,之后將這個指針從隊列中剔除,這是對象就可以安靜的死去了。.net framework的System.GC類提供了控制Finalize的兩個方法,ReRegisterForFinalize和SuppressFinalize。前者是請求系統完成對象的Finalize方法,后者是請求系統不要完成對象的Finalize方法。
ReRegisterForFinalize方法其實就是將指向對象的指針重新添加到Finalization Queue中。這就出現了一個很有趣的現象,因為在Finalization Queue中的對象可以復生,如果在對象的Finalize方法中調用ReRegisterForFinalize方法,這樣就形成了一個在堆上永遠不會死去的對象,像鳳凰涅亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美成人一二三| 久久久国产一区| 久久久久免费精品国产| 久久久最新网址| 精品成人国产在线观看男人呻吟| 国产成人高清激情视频在线观看| 国产欧美精品日韩| 久久久久久亚洲精品不卡| 91国内免费在线视频| 日韩精品久久久久| 91精品在线看| 欧美精品一区二区免费| 日韩美女写真福利在线观看| 国产精品福利无圣光在线一区| 97精品国产97久久久久久免费| 亚洲欧洲国产精品| 狠狠色狠狠色综合日日小说| 亚洲欧洲一区二区三区在线观看| 国产精品羞羞答答| 日韩国产在线看| 黑人与娇小精品av专区| 亚洲精品一区二区三区婷婷月| 亚洲成人久久久久| 久久综合免费视频| 超碰91人人草人人干| 亚洲综合小说区| 国产精品免费在线免费| 成人性生交大片免费观看嘿嘿视频| 日韩av一卡二卡| 日韩在线免费视频| 亚洲电影中文字幕| 欧美日韩亚洲国产一区| 日韩精品欧美激情| 国产亚洲精品一区二555| 亚洲毛片在线看| 国产在线播放不卡| 欧美俄罗斯性视频| 久久亚洲影音av资源网| 人人澡人人澡人人看欧美| 成人激情视频在线观看| 亚洲高清一二三区| www.久久久久久.com| 欧美黑人xxxⅹ高潮交| 国产a级全部精品| 久久久久免费视频| 日韩中文字幕精品视频| 亚洲第一精品久久忘忧草社区| 日韩视频―中文字幕| 亚洲人成网站777色婷婷| 亚洲精品99久久久久中文字幕| 国产精品久久av| 国产精品久久久久久婷婷天堂| 精品视频—区二区三区免费| 亚洲欧美精品中文字幕在线| 国产精品v片在线观看不卡| 成人a级免费视频| 国产精品国产三级国产专播精品人| 亚洲第五色综合网| 国产精品v日韩精品| 成人精品久久久| 中文字幕亚洲一区| 国产精品亚洲第一区| 亚洲毛片在线免费观看| 欧美大胆a视频| 日韩精品视频观看| 国产视频在线观看一区二区| 日韩女优人人人人射在线视频| 欧美又大粗又爽又黄大片视频| 欧美日韩在线观看视频小说| 性色av香蕉一区二区| 欧美在线亚洲一区| 国产精品揄拍500视频| 亚洲国产99精品国自产| 久久成人精品视频| 欧亚精品在线观看| 欧美极品少妇与黑人| 神马久久桃色视频| 亚洲黄色av网站| 欧美与欧洲交xxxx免费观看| 国产激情久久久| 日韩视频免费中文字幕| 亚洲xxx大片| 亚洲精品少妇网址| 久久久精品中文字幕| 亚洲激情视频在线观看| 国产精品久久久久久久久久尿| 欧美中文字幕在线视频| 九九久久久久99精品| 国产视频精品免费播放| 国产aⅴ夜夜欢一区二区三区| 2019中文字幕在线观看| 69视频在线播放| 亚洲色图综合久久| 久久天堂电影网| 国产精品免费一区豆花| 庆余年2免费日韩剧观看大牛| 国产成人在线播放| 久久精品亚洲国产| 国产精品流白浆视频| wwwwwwww亚洲| 亚洲精品国产综合久久| 欧美性高潮床叫视频| 97免费中文视频在线观看| 久久婷婷国产麻豆91天堂| 欧美激情精品久久久久久久变态| 欧美亚州一区二区三区| 国产欧美精品在线播放| 成人两性免费视频| 日韩在线视频中文字幕| 亚洲a级在线观看| 国产精品视频xxxx| 国产精品久久久久久久美男| 中文字幕一精品亚洲无线一区| 26uuu久久噜噜噜噜| 亚洲欧美国产一本综合首页| 国产日韩视频在线观看| 国产成人精品午夜| 欧美性xxxxx| 国产精品日韩久久久久| 在线日韩第一页| 国产日韩中文字幕在线| 国产久一一精品| 日韩av一区二区在线观看| 欧美在线视频播放| 97精品视频在线观看| 国产原创欧美精品| 欧美剧在线观看| 日韩经典中文字幕| 这里只有精品在线观看| 亚洲综合日韩中文字幕v在线| 欧美性生交xxxxxdddd| 国产欧美日韩专区发布| 国产精品日韩在线| 中文在线资源观看视频网站免费不卡| 日韩**中文字幕毛片| 国产视频自拍一区| 色悠悠国产精品| 日韩欧美亚洲范冰冰与中字| 日韩av手机在线看| 欧美国产精品人人做人人爱| 欧美性猛xxx| 伦理中文字幕亚洲| 欧美激情视频在线| 欧美专区国产专区| 欧美韩国理论所午夜片917电影| 激情懂色av一区av二区av| 欧美成人一区在线| 97色在线观看| 日韩视频免费大全中文字幕| 日韩在线www| 91探花福利精品国产自产在线| 国产女人精品视频| 综合欧美国产视频二区| 国产在线视频不卡| 久久久久久久久久久免费精品| 国产精品久久久久福利| 亚洲精品久久久久| 美日韩丰满少妇在线观看| 亚洲视频精品在线| 国产精品久久中文| 91亚洲精品一区| 日韩在线中文视频| 国产成人精品久久二区二区| 久久久国产视频91|