1.概述
最近通過看書系統(tǒng)的了解了JVM的GC原理,發(fā)現(xiàn)之前自己很多地方理解有偏差,不夠詳細舔箭。之前寫過一篇JVM垃圾回收機制的文章,寫的太亂了不想再后面加了案糙,所以重開一篇限嫌。這篇文章主要介紹基本概念和JVM的對象存活判定。
1.1 什么是垃圾回收
JVM會自動給我們分配內(nèi)存和釋放內(nèi)存时捌,簡單來說怒医,jvm釋放內(nèi)存的過程就是垃圾回收。這里需要注意的是:JVM回收的是“垃圾”對象所占用的內(nèi)存奢讨。
1.2 為什么要進行垃圾回收
- 避免內(nèi)存溢出稚叹、內(nèi)存泄漏
- 合理利用內(nèi)存,防止垃圾對象占用內(nèi)存
1.3 學習垃圾回收機制的意義
當需要排查各種內(nèi)存溢出拿诸、內(nèi)存泄漏問題時扒袖,當垃圾收集成為系統(tǒng)達到更高并發(fā)量的瓶頸時,我們就需要對這些“自動化”的技術實施必要的監(jiān)控和調(diào)節(jié)亩码。
2.對象存活判定
2.1 判定方法
2.1.1 引用計數(shù)法
原理
給對象添加一個引用計數(shù)器季率,當有一個地方引用該對象時,計數(shù)器值加一描沟;當引用失效時飒泻,計數(shù)器值就減一。當計數(shù)器為零時吏廉,表示該對象沒有在任何地方被引用泞遗,則該對象可以判定為可回收對象。
缺陷
無法解決循環(huán)引用的問題席覆。當兩個對象互相引用時史辙,則永遠不會被回收。
2.1.2 可達性算法
在主流語言的主流實現(xiàn)中佩伤,都是通過可達性算法來判定對象是否存活聊倔。
原理
以被稱為“GC Roots”的對象為起點,從這些節(jié)點向下搜索畦戒,搜索的路徑被稱為引用鏈方库。當對象沒有任何的引用鏈與“GC ROOTS”相連,則該對象則被判定為可回收對象障斋。
如圖,對象object 5、object 6垃环、object 7雖然互相有關聯(lián)邀层,但是它們到GC Roots是不可達的,所以它們將會被判定為是可回收的對象遂庄。
GC Roots
在java語言中寥院,可作為GC Roots的對象包括下面幾種:
- 虛擬機棧(棧幀中的本地變量表)中引用的對象
- 方法區(qū)中類靜態(tài)屬性引用的對象
- 方法區(qū)中常量引用的對象
- 本地方法棧中JNI(即一般說的Native方法)引用的對象
3.對象引用
從上面的判定算法可以看出,我們看重的是對象引用涛目。實際上在JVM中秸谢,對象引用不僅僅是有或無兩種形式。無論是哪種判定對象存活的方法霹肝,根本是在判定“引用”是否存在估蹄。java有四種引用:強引用、軟引用沫换、弱引用和虛引用臭蚁。
名稱 | 定義 | 回收情況 |
---|---|---|
強引用 | 一般使用的引用,比如new出來的對象讯赏,即“Object object = new Object()” | 在對象沒有被根引用鏈接的時候被回收 |
軟引用 | 有用但非必須的對象垮兑,比如一些緩存對象 | 在系統(tǒng)將要發(fā)生內(nèi)存溢出前,才會將這些引用列入回收范圍漱挎,進行一次回收操作系枪。在這次回收之后,系統(tǒng)仍然還沒有足夠的內(nèi)存磕谅,才會拋出內(nèi)存溢出異常 |
弱引用 | 用來描述非必須對象私爷,強度低于軟引用 | 只存活到下一次垃圾回收之前,當垃圾回收開始怜庸,無論內(nèi)存是否足夠当犯,都會回收 |
虛引用 | 為一個對象設置虛引用關聯(lián)的唯一目的就是能在這個對象被收集器回收時收到一條系統(tǒng)通知。 | 一個對象有無虛引用割疾,不影響他生存時間嚎卫;通過一個虛引用也無法獲取一個對象實例 |
4.對象被回收過程
finalize方法中,可將待回收對象賦值給GC Roots可達的對象引用宏榕,從而達到對象再生的目的
需要注意的是拓诸,任何一個對象的finalize()方法都只會被系統(tǒng)自動調(diào)用一次,如果對象面臨下一次回收麻昼,它的finalize()方法不會被再次執(zhí)行奠支,即對象只能自救一次。
5.方法區(qū)回收
這里說的方法區(qū)抚芦,在hotspot中叫做“永久代”倍谜,java虛擬機規(guī)范中不要求一定要實現(xiàn)方法區(qū)的垃圾回收迈螟。原因主要是由于方法區(qū)回收的性價比太低。
5.1 方法區(qū)垃圾主要內(nèi)容
5.1.1 廢棄常量
以常量池中字面量的回收為例尔崔,假如一個字符串"abc"已經(jīng)進入了常量池中答毫,沒有任何String對象引用常量池中的"abc"常量,也沒有其他地方引用了這個字面量季春,這個"abc"常量就會被系統(tǒng)清理出常量池
5.1.2 無用的類
同時滿足下面三個條件可以回收:
- 該類所有的實例都已經(jīng)被回收洗搂,即Java堆中不存在該類的任何實例
- 加載該類的ClassLoader已經(jīng)被回收
- 該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法
需要注意的是载弄,這里說的是“可以回收”耘拇,而不是一定回收。類的回收和對象的回收不一樣的地方就在此宇攻。是否對類進行回收惫叛,HotSpot虛擬機提供了-Xnoclassgc參數(shù)進行控制。
還可以使用-verbose:class以及-XX:+TraceClassLoading尺碰、
-XX:+TraceClassUnLoading查看類加載和卸載信息挣棕,其中-verbose:class和-XX:+TraceClassLoading可以在Product版的虛擬機中使用,-XX:+TraceClassUnLoading參數(shù)需要FastDebug版的虛擬機支持亲桥。