個人認為垃圾回收機制是java語言最棒的功能之一。正是有垃圾回收機制的存在,使得java程序員不必要費心考慮內存泄漏問題(當然還是有內存泄漏的可能性存在的),這不僅僅是少寫一句delete()的問題。java語言的垃圾回收機制是和java的單根繼承體系以及對象空間分配等機制緊密聯系的。可以說是java語言整個的體系結構造就了這么出色的垃圾回收機制。至于c++,Bjarne Stroustrup在他的faq中提及垃圾回收的問題。他聲稱現在有一些不錯的商業的和公共域的垃圾回收器,而且在垃圾回收器適用的程序中C++的垃圾收集和其他支持垃圾收集的語言相比性能更好。另外C++還支持其他內存管理技術,不用垃圾收集也可以安全地隱式地管理內存。可惜自己c++太菜了,要努力學習,好好研究一下。

垃圾回收是一種動態存儲管理技術,它自動地釋放不再被程序引用的對象,按照特定的垃圾收集算法來實現資源自動回收的功能。java程序員不需要考慮太多內存的管理,虛擬機會自動在內存緊張的時候進行垃圾回收的操作。釋放資源的同時,垃圾回收機制也會清楚內存中的碎片。這個功能可以提升對象空間分配的效率,因為垃圾回收會將內存中的對象緊密排列,新對象的分配只要將堆指針簡單前移就行了,不需要遍歷堆來查找合適大小的內存塊。這樣java在堆中分配空間的效率甚至可以逼近在棧中的分配效率。

但是垃圾回收在釋放資源的時候仍然會占用大量資源。效率的高低與垃圾回收機制所使用的算法有關系。

垃圾回收最單純直觀的算法就是引用計數法。每個對象都有一個引用計數表。增加一個對該對象的引用,計數加一,反之減一。垃圾回收的時候,即將引用計數為0的對象釋放。這種算法速度很慢。因為垃圾回收器要遍歷內存中的所有對象,并在發現引用計數為零的時候將其釋放。另外對于循環交互引用的一群對象,如果整群對象都已經成為垃圾,那么仍然有可能存在非零的計數。所以引用計數幾乎沒有被用于任何真正的虛擬機上。

實際中使用的算法是:從棧和靜態存儲空間中的reference出發,訪問他們指向的對象,以及這些對象內部引用到的對象。整個過程中訪問到的對象即還存活的對象,未訪問到的自然成了垃圾。在處理對象的時候,有眾多的機制。其中主要的是“stop-and copy”,“mark and sweep”和“generation”。

stop-and-copy即將找到的對象從正在執行的程序中停下來,然后copy到新的堆中。同時將對該對象的reference指向新的地址。這種做法使得對象在新堆中排列緊湊。但是也存在若干的問題。這種機制要維護兩個堆,對象在兩個堆之間copy,因此使用該機制要占用的內存是實際需要的兩倍。另外,若程序只產生很少的垃圾,而垃圾回收仍然會將對象copy到新堆中,嚴重影響了程序的執行效率。

mark and sweep也是從棧和靜態存儲空間出發,對找到的對象進行標記。整個標記過程結束后再進行清理,沒有標記的對象將被清理。這種方式會產生不連續的內存塊。要使得內存排列緊密,必須重新進行整理工作。以上的兩種做法都要在中止程序的情況下進行。

generation方法將內存分成若干的大塊,稱為generation。每塊中會有世代紀錄。新出現的塊更“年輕”。每次垃圾回收之后,將年輕塊中存活的對象移到比該塊年長的塊中。這種方法適用于處理數量極大而生命短暫的小對象。比較穩定的對象會處于年長的塊中,不會被復制,只會改動其世代紀錄。

虛擬機通常采用自省式的垃圾處理機制。他會根據當時的內存情況選擇適當的垃圾回收機制。比如內存對象穩定時即采用mark-and-sweep,減少copy次數。如果內存中碎片過多,即采用stop-and-copy的方法使內存緊湊。