如何判斷對象是否存活
引用計數法
概念
- 引用計數法就是如果一個對象沒有被任何引用指向,則可視之為垃圾。這種方法的缺點就是不能檢測到環的存在。
- 首先需要聲明,至少主流的Java虛擬機里面都沒有選用引用計數算法來管理內存。
什么是引用計數算法:
- 給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值加1;
- 當引用失效時,計數器值減1.任何時刻計數器值為0的對象就是不可能再被使用的。
那為什么主流的Java虛擬機里面都沒有選用這種算法呢?
其中最主要的原因是它很難解決對象之間相互循環引用的問題。
根搜索算法
概念
- 這個算法的基本思想是通過一系列稱為“GC Roots”的對象作為起始點,從這些節點向下搜索,搜索所走過的路徑稱為引用鏈,當一個對象到GC Roots沒有任何引用鏈(即GC Roots到對象不可達)時,則證明此對象是不可用的。
那么問題又來了,如何選取GCRoots對象呢?
在Java語言中,可以作為GCRoots的對象包括下面幾種:
(1). 虛擬機棧(棧幀中的局部變量區,也叫做局部變量表)中引用的對象。
(2). 方法區中的類靜態屬性引用的對象。
(3). 方法區中常量引用的對象。
(4). 本地方法棧中JNI(Native方法)引用的對象。
下面給出一個GCRoots的例子,如下圖,為GCRoots的引用鏈。
舉例分析,看下面的圖:
根搜索算法的基本思路就是通過一系列名為”GC Roots”的對象作為起始點,從這些節點開始向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象是不可用的。
從上圖,reference1、reference2、reference3都是GC Roots,可以看出:
- reference1-> 對象實例1;
- reference2-> 對象實例2;
- reference3-> 對象實例4;
- reference3-> 對象實例4 -> 對象實例6;
可以得出對象實例1、2、4、6都具有GC Roots可達性,也就是存活對象,不能被GC回收的對象。
而對於對象實例3、5直接雖然連通,但並沒有任何一個GC Roots與之相連,這便是GC Roots不可達的對象,這就是GC需要回收的垃圾對象。
引用計數法 已經被淘汰了!因為循環依賴問題!
A a = new A() 每個對象有個年齡 大於了一定年齡(15) 存放老年代 否則 新生代
GC線程不定時進行回收,如果對象被應用的話,年齡就+1,如果沒有被繼續回收則-1
如果年齡為0的話,被回收
循環依賴問題:
A a = new A()
B b = new B()
a.x=b
b.x=a
a=null
b=null
很難判斷 然后 怎么去標記為0 去回收
根搜索算法 GCRoots 沒有和GCRoots 需要和根節點有依賴關系 如果沒有和GCRoots有任何引用關系情況,GC認為不可達對象。
遍歷一遍看看 與GCRoots有引用沒
只有 user3和user5 不可達 。