虛擬機的回收算法按照基本回收策略分爲以下四種:
1. 引用計數
原理是此對象有一個引用就增加一個計數,刪除一個引用則減少一個計數。垃圾回收時,只回收計數爲0的對象。
缺點:無法處理循環引用的問題
2. 標記-清除 , 是老年代(Tenured)的主要回收算法
此算法執行分兩階段:
1. 從引用根節點開始標記所有被引用的對象
2. 遍歷整個堆,把未標記的對象清除。
缺點:此算法需要暫停整個應用,會產生內存碎片
3.複製,是年輕代的主要垃圾回收算法
此算法把內存空間劃爲兩個相等的區域,每次只使用其中一個區域。
垃圾回收時,遍歷當前使用區域,把正在使用中的對象複製到另外一個區域,之後進行相應的內存整理,不會出現碎片問題。
缺點:需要兩倍內存空間
4. 標記-整理
在標記-清除之後重新整理內存,避免了內存碎片問題和複製算法的空間問題
內存碎片會導致無法分配大塊的內存空間以及程序運行效率降低
哪些對象可以被稱爲“垃圾”
垃圾回收的起點是一些根對象:
1.沒有被任何外部對象引用的棧中的對象,即系統內運行的所有線程分配在棧中的變量,該對象就是“根”
一旦線程跑到某一個變量所在的作用域之外,那麼該變量就變成了垃圾
2.靜態變量在任何時候都是“根”對象
3.寄存器
根據這些根集對象檢測所有對象的可達性即可判斷對象是否可以回收
可達性:某個對象的內存地址是否有被引用
把一個對象置爲NULL並不能保證該對象會被回收
測試類:
public class TestNull {
public static void main(String[] args) {
Map<String, Object> map = new HashMap<>();
Object obj = new Object();
map.put("obj", obj);
obj = null;
System.out.println(map.get("obj"));
}
}
運行可以看到map仍然可以引用到obj,分析如圖:
因爲HashMap仍然引用了new Object()對象,所以其並不會被JVM回收
tips:
1.如果希望集合中的對象被回收,調用其相應的remove()方法從集合中刪掉即可
2.obj = null;語義是把讓變量obj不再指向任何物理內存
而不是把obj所指向的對象的物理內存置爲null