Java对象垃圾回收调用,JVM垃圾回收之哪些对象可以被回收
1.背景
Java語言相比于C和C++,一個最大的特點就是不需要程序員自己手動去申請和釋放內存,這一切交由JVM來完成。在Java中,運行時的數據區域分為程序計數器、Java虛擬機棧、本地方法棧、方法區和堆。其中,程序計數器、虛擬機棧和本地方法棧是線程私有的,線程銷毀后自動釋放。垃圾回收的行為發生在堆和方法區,主要是堆,而堆中存儲的主要是對象。那么自然而然地就會有這么幾個問題,哪些對象可以被回收?通過什么方式回收?本文主要探討第一個問題,以及JVM對Java中幾種引用的回收策略。
2.如何判斷一個對象是否可以被回收 2.1 引用計數法
主要思想是:給對象添加一個引用計數器,這個對象被引用一次,計數器就加1;不再引用了,計數器就減1。如果一個對象的引用計數器為0,說明沒有人使用這個對象,那么這個對象就可以被回收了。這種方法實現起來比較簡單,效率也比較高,大多數情況下都是有效的。但是,這種方法有一個漏洞。比如A.property = B,B.property = A,A和B兩個對象互相引用,并且沒有其他對象引用A和B。按照引用計數法的思想,A和B對象的引用計數器都不為0,都不能被釋放,但實際情況是A和B已經沒人使用他們了,這就造成了內存泄漏。所以,引用計數法雖然實現簡單,但并不是一個完美的解決方案,實際中的Java也沒有采用它。
2.2 可達性分析算法
主要思想是:首先確定確定一系列肯定不能被回收的對象,即GC Roots。然后,從這些GC Roots出發,向下搜索,去尋找它直接和間接引用的對象。最后,如果一個對象沒有被GC Roots直接或間接地引用,那么這個對象就可以被回收了。這種方法可以有效解決循環引用的問題,實際中Java也是采用這種判斷方法。那么問題來了,哪些對象可以作為GC Roots呢?這里可以使用MAT工具進行觀察。運行下面的demo:
import java.util.concurrent.TimeUnit; public class GCRootsTest { public static void main(String[] args) throws InterruptedException { Object o = new Object(); TimeUnit.SECONDS.sleep(100); }}
主線程sleep的時候,在terminal窗口執行jmap -dump:format=b,live,file=heapdump.bin 2872命令,生成堆轉儲快照dump文件,其中2872是進程id,可以使用jps命令查看。然后使用MAT工具打開dump文件,可以很明顯地看到一共有四類對象可以作為GC Roots,下面詳細介紹下。
第一類,系統類對象(System Class)。比如,java.lang.String的Class對象,這個也很好理解,如果這些核心的系統類對象被回收了,程序就沒辦法運行了。
第二類,native方法引用的對象。
第三類,活動線程中正在引用的對象??梢钥闯?#xff0c;代碼中變量o指向的Object對象可以被當作GC Roots。
第四類,正在加鎖的對象。
3.Java中的幾種引用
在可達性分析算法中,判斷一個對象是不是可以被回收,主要看從GC Roots出發是否可以找到一個引用指向該對象。java中的引用一共有四種,按照引用的強弱依次為強引用(Strong Reference)、軟引用(Soft Reference)、弱引用(Weak Reference)、虛引用(Phantom Reference)。這樣就可以對不同引用指向的對象采取不同的回收策略。比如一個強引用指向一個對象,那么這個對象肯定不會被回收,哪怕發生OOM。而對于弱引用指向的對象,只要發生垃圾回收,該對象就會被回收。下面詳細介紹下不同引用的用法。
3.1強引用
所謂強引用,就是平時使用最多的,類似于Object obj = new Object()的引用。垃圾回收器永遠不會回收被強引用指向的對象。
3.2軟引用
軟引用,在Java中使用SoftReference類來實現軟引用。在下面的代碼中,softReference作為軟用指向一個Object對象,而otherObject變量可以通過軟引用的get方法間接引用到Object對象。
public static void main(String[] args) { // 軟引用 SoftReference
總結
以上是生活随笔為你收集整理的Java对象垃圾回收调用,JVM垃圾回收之哪些对象可以被回收的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++ qt获取电脑的内存_Qt官方示例
- 下一篇: C++ string转字符串