垃圾收集(Garbage Colection,GC),需要完成三件事情:
- 哪些記憶體需要回收?
- 什麼時候回收?
- 如何回收?
垃圾收集器主要關注Java堆和方法區這兩部分記憶體,本章後續讨論中的“記憶體”配置設定與回收也僅指這一部分記憶體。
哪些記憶體需要回收
Java堆裡存放着Java世界中幾乎所有的對象執行個體,垃圾收集器在對堆進行回收前,第一件事情就是要确定這些對象之中哪些還“存活”着,哪些已經“死去”(即不可能再被任何途徑使用的對象)。
-
引用計數算法
給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時刻計數器為0的對象就是不可能再被使用的。
引用計數算法實作簡單,判定效率也很高,但是主流的Java虛拟機裡面沒有選用引用計數算法來管理記憶體,其中最主要的原因是它很難解決對象之間互相循環引用的問題。
-
可達性分析算法
在主流的商用程式語言的主流實作中,都是通過可達性分析來判定對象是否存活的。
這個算法的基本思路就是通過一系列的稱為“GC Roots”的對象作為起始點,從這些節點開始向下搜尋,搜尋所走過的路經成為引用鍊,當一個對想到GC Roots沒有任何引用鍊相連(用圖論的話來說,就是從GC Roots到這個對象不可達)時,則證明此對象時不可用的。

在Java語言中,可作為GC Roots的對象包括下main幾種:
- 虛拟機棧(棧幀中的本地變量表)中引用的對象。
- 方法區中類靜态屬性引用的對象。
- 方法去中常量引用的對象。
- 本地方法棧中JNI(即一般說的Native方法)引用的對象。
-
回收方法區
很多人認為方法區(或者HotSpot虛拟機中的永久代)是沒有垃圾收集的,Java虛拟機規範中确實受過可以不要求虛拟機在方法區實作垃圾收集,而且在方法去中進行垃圾收集的“成本效益”一般比較低:在堆中,尤其是在新生代中,正常應用進行一次垃圾收集一般可以回收70%~95%的空間,而永久代的垃圾收集效率遠低于此。
方法區的垃圾回收主要回收兩部分内容:廢棄常量和無用的類。
類需要同時滿足下面3個條件才算是“無用的類”:
- 該類所有的執行個體都已經被回收,也就是Java堆中不存在該類的任何執行個體。
- 加載該類的ClassLoader已經被回收。
- 該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射通路該類的方法。
虛拟機可以對滿足上述3個條件的無用類進行回收,這裡說的僅僅是“可以”,而并不是和對象一樣,不使用了就必然會回收。是否對類進行回收,HotSpot虛拟機提供了一些參數控制類加載和解除安裝資訊。在大量使用反射、動态代理、CGLib等ByteCode架構、動态生成JSP以及OSGi這類頻繁自定義ClassLoader的場景都需要虛拟機具備類解除安裝的功能,以保證永久代不會溢出。