jvm性能调优 - 03垃圾回收机制
文章目錄
- Pre
- 對象的分配與引用
- 一個(gè)方法執(zhí)行完畢之后會怎么樣?
- 不再需要的那些對象應(yīng)該怎么處理?--GC
- 思考題
Pre
上一篇文章給大家分析了JVM中的幾塊內(nèi)存區(qū)域分別都是干什么的,今天的文章就給大家初步介紹一下垃圾回收的概念。
先來看一下昨天的一張圖,回顧一下JVM中幾塊內(nèi)存區(qū)域的作用。
大家腦子里一定要有一個(gè)會動(dòng)的圖,你的代碼在運(yùn)行的時(shí)候,起碼有一個(gè)main線程會去執(zhí)行所有的代碼,當(dāng)然也可能是你啟動(dòng)的別的線程。
然后線程執(zhí)行時(shí)必須通過自己的程序計(jì)數(shù)器來記錄執(zhí)行到哪一個(gè)代碼指令了
另外線程在執(zhí)行方法時(shí),為每個(gè)方法都得創(chuàng)建一個(gè)棧幀放入自己的Java虛擬機(jī)棧里去,里面有方法的局部變量。
最后就是代碼運(yùn)行過程中創(chuàng)建的各種對象,都是放在Java堆內(nèi)存里的。
結(jié)合上面的大圖看一看,相信大家一定就明白是怎么回事了,大家對JVM的運(yùn)行原理也應(yīng)該都有了一個(gè)初步的理解和把握。
對象的分配與引用
現(xiàn)在我們假設(shè)有下面一段代碼,大概意思你可以理解為通過“l(fā)oadReplicasFromDisk”方法的執(zhí)行,去磁盤上加載需要的副本數(shù)據(jù)
然后通過“ReplicaManager”對象實(shí)例完成了這個(gè)操作。
代碼如下所示:
結(jié)合我們之前理解過的JVM運(yùn)行原理,一起通過動(dòng)態(tài)的圖來拆解一下上述代碼的運(yùn)行流程。
首先一個(gè)main線程肯定會來執(zhí)行main()方法里的代碼
main線程自己是有一個(gè)Java虛擬機(jī)棧的,他會把main()方法的棧幀壓入Java虛擬機(jī)棧,如下圖
接著main()方法里調(diào)用了loadReplicasFromDisk()方法
那么就會創(chuàng)建loadReplicasFromDisk()方法的棧幀,壓入main線程的Java虛擬機(jī)棧里去
這個(gè)過程如下圖:
此時(shí)發(fā)現(xiàn)在loadReplicasFromDisk()方法里,有一個(gè)“repliaManager”變量,那么就會在loadReplicasFromDisk()方法對應(yīng)的棧幀里,放入一個(gè)“repliaManager”變量。
接著發(fā)現(xiàn)在代碼里創(chuàng)建了一個(gè)“ReplicaManager”類的實(shí)例對象,此時(shí)就會在Java堆內(nèi)存中分配這個(gè)實(shí)例對象的內(nèi)存空間。
同時(shí),讓loadReplicasFromDisk()方法的棧幀內(nèi)的“replicaManager”局部變量去指向那個(gè)Java堆內(nèi)存里的ReplicaManager實(shí)例對象,大家看下圖:
接下來,就會執(zhí)行通過“replicaManager”局部變量引用的“ReplicaManager”實(shí)例對象去執(zhí)行他的load()方法,去完成我們實(shí)現(xiàn)的業(yè)務(wù)邏輯。
好,到這里為止,其實(shí)都是上篇文章講解過的知識,我們就是重新串聯(lián)了一遍 ~
一個(gè)方法執(zhí)行完畢之后會怎么樣?
接著大家來回顧一下上面的代碼。
其實(shí)目前的圖我們已經(jīng)表述到了“replicaManager.load()”這行代碼這里
那么現(xiàn)在有個(gè)問題,如果這行代碼執(zhí)行結(jié)束了,此時(shí)會怎么樣? 一旦方法里的代碼執(zhí)行完畢,那么方法就執(zhí)行完畢了,也就是說loadReplicasFromDisk()方法就執(zhí)行完畢了。
一旦你的loadReplicasFromDisk()方法執(zhí)行完畢,此時(shí)就會把loadReplicasFromDisk()方法對應(yīng)的棧幀從main線程的Java虛擬機(jī)棧里出棧
此時(shí)一旦loadReplicasFromDisk()方法的棧幀出棧,那么大家會發(fā)現(xiàn)那個(gè)棧幀里的局部變量,“replicaManager”,也就沒有了。
也就是說,沒有任何一個(gè)變量指向Java堆內(nèi)存里的“ReplicaManager”實(shí)例對象了。
核心點(diǎn)來了,此時(shí)大家發(fā)現(xiàn)了,Java堆內(nèi)存里的那個(gè)“ReplicaManager”實(shí)例對象已經(jīng)沒有人引用他了
這個(gè)對象實(shí)際上已經(jīng)沒用了,該干的事兒都干完了,現(xiàn)在你還讓他留在內(nèi)存里干啥呢?
大家要知道,內(nèi)存資源是有限的。
一般來說,我們會在一臺機(jī)器上啟動(dòng)一個(gè)Java系統(tǒng),機(jī)器的內(nèi)存資源是有限的,比如就4個(gè)G的內(nèi)存
然后我們啟動(dòng)的Java系統(tǒng)本質(zhì)就是一個(gè)JVM進(jìn)程,他負(fù)責(zé)運(yùn)行我們的系統(tǒng)的代碼 。
那么這個(gè)JVM進(jìn)程本身也是會占用機(jī)器上的部分內(nèi)存資源,比如占用2G的內(nèi)存資源。
那么我們在JVM的Java堆內(nèi)存中創(chuàng)建的對象,其實(shí)本質(zhì)也是會占用JVM的內(nèi)存資源的,比如“ReplicaManager”實(shí)例對象,會占用500字節(jié)的內(nèi)存。
所以大家看到這里,心中應(yīng)該無比明白的一個(gè)核心點(diǎn):我們在Java堆內(nèi)存里創(chuàng)建的對象,都是占用內(nèi)存資源的,而且內(nèi)存資源有限。
不再需要的那些對象應(yīng)該怎么處理?–GC
繼續(xù)思考上面的圖,既然“ReplicaManager”對象實(shí)例是不需要使用的,已經(jīng)沒有任何方法的局部變量在引用這個(gè)實(shí)例對象了,而且他還空占著內(nèi)存資源,那么我們應(yīng)該怎么處理呢?
JVM的垃圾回收機(jī)制
JVM本身是有垃圾回收機(jī)制的,他是一個(gè)后臺自動(dòng)運(yùn)行的線程
你只要啟動(dòng)一個(gè)JVM進(jìn)程,他就會自帶這么一個(gè)垃圾回收的后臺線程。
這個(gè)線程會在后臺不斷檢查JVM堆內(nèi)存中的各個(gè)實(shí)例對象
還是給大家畫一張圖,來看看這個(gè)過程:
如果某個(gè)實(shí)例對象沒有任何一個(gè)方法的局部變量指向他,也沒有任何一個(gè)類的靜態(tài)變量,包括常量等地方在指向他。
那么這個(gè)垃圾回收線程,就會把這個(gè)沒人指向的“ReplicaManager”實(shí)例對象給回收掉,從內(nèi)存里清除掉,讓他不再占用任何內(nèi)存資源。
這樣的話,這些不再被人指向的對象實(shí)例,即JVM中的“垃圾”,就會定期的被后臺垃圾回收線程清理掉,不斷釋放內(nèi)存資源
到此為止,相信大家跟上文章思路一路看下來,就很清晰明了。到底什么是JVM中的“垃圾”?什么又是JVM的“垃圾回收”!
思考題
既然今天提到了Java堆內(nèi)存里的對象會被回收掉,那么加載到方法區(qū)的類會被垃圾回收嗎?什么時(shí)候被回收?為什么呢?
-
首先該類的所有實(shí)例對象都已經(jīng)從Java堆內(nèi)存里被回收
-
其次加載這個(gè)類的ClassLoader已經(jīng)被回收
-
最后,對該類的Class對象沒有任何引用
滿足上面三個(gè)條件就可以回收該類了
總結(jié)
以上是生活随笔為你收集整理的jvm性能调优 - 03垃圾回收机制的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jvm性能调优 - 02JVM中内存区域
- 下一篇: jvm性能调优 - 05对象在JVM内存