個(gè)人認(rèn)為垃圾回收機(jī)制是java語(yǔ)言最棒的功能之一。正是有垃圾回收機(jī)制的存在,使得java程序員不必要費(fèi)心考慮內(nèi)存泄漏問(wèn)題(當(dāng)然還是有內(nèi)存泄漏的可能性存在的),這不僅僅是少寫(xiě)一句delete()的問(wèn)題。java語(yǔ)言的垃圾回收機(jī)制是和java的單根繼承體系以及對(duì)象空間分配等機(jī)制緊密聯(lián)系的。可以說(shuō)是java語(yǔ)言整個(gè)的體系結(jié)構(gòu)造就了這么出色的垃圾回收機(jī)制。至于c++,Bjarne Stroustrup在他的faq中提及垃圾回收的問(wèn)題。他聲稱(chēng)現(xiàn)在有一些不錯(cuò)的商業(yè)的和公共域的垃圾回收器,而且在垃圾回收器適用的程序中C++的垃圾收集和其他支持垃圾收集的語(yǔ)言相比性能更好。另外C++還支持其他內(nèi)存管理技術(shù),不用垃圾收集也可以安全地隱式地管理內(nèi)存。可惜自己c++太菜了,要努力學(xué)習(xí),好好研究一下。
垃圾回收是一種動(dòng)態(tài)存儲(chǔ)管理技術(shù),它自動(dòng)地釋放不再被程序引用的對(duì)象,按照特定的垃圾收集算法來(lái)實(shí)現(xiàn)資源自動(dòng)回收的功能。java程序員不需要考慮太多內(nèi)存的管理,虛擬機(jī)會(huì)自動(dòng)在內(nèi)存緊張的時(shí)候進(jìn)行垃圾回收的操作。釋放資源的同時(shí),垃圾回收機(jī)制也會(huì)清楚內(nèi)存中的碎片。這個(gè)功能可以提升對(duì)象空間分配的效率,因?yàn)槔厥諘?huì)將內(nèi)存中的對(duì)象緊密排列,新對(duì)象的分配只要將堆指針簡(jiǎn)單前移就行了,不需要遍歷堆來(lái)查找合適大小的內(nèi)存塊。這樣java在堆中分配空間的效率甚至可以逼近在棧中的分配效率。
但是垃圾回收在釋放資源的時(shí)候仍然會(huì)占用大量資源。效率的高低與垃圾回收機(jī)制所使用的算法有關(guān)系。
垃圾回收最單純直觀的算法就是引用計(jì)數(shù)法。每個(gè)對(duì)象都有一個(gè)引用計(jì)數(shù)表。增加一個(gè)對(duì)該對(duì)象的引用,計(jì)數(shù)加一,反之減一。垃圾回收的時(shí)候,即將引用計(jì)數(shù)為0的對(duì)象釋放。這種算法速度很慢。因?yàn)槔厥掌饕闅v內(nèi)存中的所有對(duì)象,并在發(fā)現(xiàn)引用計(jì)數(shù)為零的時(shí)候?qū)⑵溽尫?。另外?duì)于循環(huán)交互引用的一群對(duì)象,如果整群對(duì)象都已經(jīng)成為垃圾,那么仍然有可能存在非零的計(jì)數(shù)。所以引用計(jì)數(shù)幾乎沒(méi)有被用于任何真正的虛擬機(jī)上。
實(shí)際中使用的算法是:從棧和靜態(tài)存儲(chǔ)空間中的reference出發(fā),訪(fǎng)問(wèn)他們指向的對(duì)象,以及這些對(duì)象內(nèi)部引用到的對(duì)象。整個(gè)過(guò)程中訪(fǎng)問(wèn)到的對(duì)象即還存活的對(duì)象,未訪(fǎng)問(wèn)到的自然成了垃圾。在處理對(duì)象的時(shí)候,有眾多的機(jī)制。其中主要的是“stop-and copy”,“mark and sweep”和“generation”。
stop-and-copy即將找到的對(duì)象從正在執(zhí)行的程序中停下來(lái),然后copy到新的堆中。同時(shí)將對(duì)該對(duì)象的reference指向新的地址。這種做法使得對(duì)象在新堆中排列緊湊。但是也存在若干的問(wèn)題。這種機(jī)制要維護(hù)兩個(gè)堆,對(duì)象在兩個(gè)堆之間copy,因此使用該機(jī)制要占用的內(nèi)存是實(shí)際需要的兩倍。另外,若程序只產(chǎn)生很少的垃圾,而垃圾回收仍然會(huì)將對(duì)象copy到新堆中,嚴(yán)重影響了程序的執(zhí)行效率。
mark and sweep也是從棧和靜態(tài)存儲(chǔ)空間出發(fā),對(duì)找到的對(duì)象進(jìn)行標(biāo)記。整個(gè)標(biāo)記過(guò)程結(jié)束后再進(jìn)行清理,沒(méi)有標(biāo)記的對(duì)象將被清理。這種方式會(huì)產(chǎn)生不連續(xù)的內(nèi)存塊。要使得內(nèi)存排列緊密,必須重新進(jìn)行整理工作。以上的兩種做法都要在中止程序的情況下進(jìn)行。
generation方法將內(nèi)存分成若干的大塊,稱(chēng)為generation。每塊中會(huì)有世代紀(jì)錄。新出現(xiàn)的塊更“年輕”。每次垃圾回收之后,將年輕塊中存活的對(duì)象移到比該塊年長(zhǎng)的塊中。這種方法適用于處理數(shù)量極大而生命短暫的小對(duì)象。比較穩(wěn)定的對(duì)象會(huì)處于年長(zhǎng)的塊中,不會(huì)被復(fù)制,只會(huì)改動(dòng)其世代紀(jì)錄。
虛擬機(jī)通常采用自省式的垃圾處理機(jī)制。他會(huì)根據(jù)當(dāng)時(shí)的內(nèi)存情況選擇適當(dāng)?shù)睦厥諜C(jī)制。比如內(nèi)存對(duì)象穩(wěn)定時(shí)即采用mark-and-sweep,減少copy次數(shù)。如果內(nèi)存中碎片過(guò)多,即采用stop-and-copy的方法使內(nèi)存緊湊。