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