最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

008、聊聊JVM分代模型:年輕代、老年代、永久代

2023-06-01 15:36 作者:儒猿課堂  | 我要投稿


聊聊 JVM 分代模型:年輕代、老年代、永久代


目錄:

  1. 背景引入

  2. 大部分對(duì)象其實(shí)存活周期極短

  3. 少數(shù)對(duì)象是長(zhǎng)期存活的

  4. JVM分代模型:年輕代和老年代

  5. 為什么要分成年輕代和老年代?

  6. 什么是永久代?

  7. 上周思考題解答

  8. 今日思考題


1、背景引入

今天開(kāi)始,咱們進(jìn)入第二周的內(nèi)容,這一周會(huì)重點(diǎn)關(guān)注JVM內(nèi)存劃分的一些細(xì)節(jié)。

我會(huì)幫助大家更加深入的去理解JVM內(nèi)存劃分的原理細(xì)節(jié),以及我們創(chuàng)建的那些對(duì)象在JVM中到底是如何分配,如何流動(dòng)的,這對(duì)于大家理解JVM原理有更深一層的幫助。

首先這篇文章作為本周的一個(gè)開(kāi)篇,我們來(lái)給大家介紹一下JVM內(nèi)存的一個(gè)分代模型:年輕代、老年代、永久代。

大家現(xiàn)在應(yīng)該都知道一點(diǎn),那就是我們?cè)诖a里創(chuàng)建的對(duì)象,都會(huì)進(jìn)入到Java堆內(nèi)存中,比如下面的代碼:



這段代碼,我們稍微做了點(diǎn)改動(dòng),在main()方法里,會(huì)周期新的執(zhí)行loadReplicasFromDisk()方法,加載副本數(shù)據(jù)。

首先一旦執(zhí)行main()方法,那么就會(huì)把main()方法的棧幀壓入main線程的Java虛擬機(jī)棧

如下圖。

然后每次在while循環(huán)里,調(diào)用loadReplicasFromDisk()方法,就會(huì)把loadReplicasFromDisk()方法的棧幀壓入自己的Java虛擬機(jī)棧

如下圖。

接著在執(zhí)行l(wèi)oadReplicasFromDisk()方法的時(shí)候,會(huì)在Java堆內(nèi)存里會(huì)創(chuàng)建一個(gè)ReplicaManager對(duì)象實(shí)例

而且loadReplicasFromDisk()方法的棧幀里會(huì)有“replicaManager”局部變量去引用Java堆內(nèi)存里的ReplicaManager對(duì)象實(shí)例

如下圖:

然后就會(huì)執(zhí)行ReplicaManager對(duì)象的load()方法。


2、大部分對(duì)象都是存活周期極短的

現(xiàn)在有一個(gè)問(wèn)題,在上面代碼中,那個(gè)ReplicaManager對(duì)象,實(shí)際上屬于短暫存活的這么一個(gè)對(duì)象

大家可以觀察一下,在loadReplicasFromDisk()方法中創(chuàng)建這個(gè)對(duì)象,然后執(zhí)行ReplicaManager對(duì)象的load()方法,然后執(zhí)行完畢之后,loadReplicasFromDisk()方法就會(huì)結(jié)束。

一旦方法結(jié)束,那么loadReplicasFromDisk()方法的棧幀就會(huì)出棧,如下圖。

然后接著上篇文章已經(jīng)說(shuō)過(guò),此時(shí)一旦沒(méi)人引用這個(gè)ReplicaManager對(duì)象了,就會(huì)被JVM的垃圾回收線程給回收掉,釋放內(nèi)存空間,如下圖。

然后在main()方法的while循環(huán)里,下一次循環(huán)再次執(zhí)行loadReplicasFromDisk()方法的時(shí)候,又會(huì)走一遍上面那個(gè)過(guò)程,把loadReplicasFromDisk()方法的棧幀壓入Java虛擬機(jī)棧,然后構(gòu)造一個(gè)ReplicaManager實(shí)例對(duì)象放在Java堆里。

一旦執(zhí)行完ReplicaManager對(duì)象的load()方法之后,loadReplicasFromDisk()方法又會(huì)結(jié)束,再次出棧,然后垃圾回收釋放掉Java堆內(nèi)存里的ReplicaManager對(duì)象。

所以其實(shí)這個(gè)ReplicaManager對(duì)象,在上面的代碼中,是一個(gè)存活周期極為短暫的對(duì)象

可能每次執(zhí)行l(wèi)oadReplicasFromDisk()方法的時(shí)候,被創(chuàng)建出來(lái),然后執(zhí)行他的load()方法,接著可能1毫秒之后,就被垃圾回收掉了。

所以從這段代碼就可以明顯看出來(lái),大部分在我們代碼里創(chuàng)建的對(duì)象,其實(shí)都是存活周期很短的。這種對(duì)象,其實(shí)在我們寫(xiě)的Java代碼中,占到絕大部分的比例。


3、少數(shù)對(duì)象是長(zhǎng)期存活的

但是我們來(lái)看另外一段代碼,假如說(shuō)咱們用下面的這種方式來(lái)實(shí)現(xiàn)同樣的功能:

上面那段代碼的意思,就是給Kafka這個(gè)類(lèi)定義一個(gè)靜態(tài)變量,也就是“replicaManager”,這個(gè)Kafka類(lèi)是在JVM的方法區(qū)里的

然后讓“replicaManager”引用了一個(gè)在Java堆內(nèi)存里創(chuàng)建的ReplicaManager實(shí)例對(duì)象,如下圖。

接著在main()方法中,就會(huì)在一個(gè)while循環(huán)里,不停的調(diào)用ReplicaManager對(duì)象的load()方法,做成一個(gè)周期性運(yùn)行的模式。

這個(gè)時(shí)候,我們就要來(lái)思考一下,這個(gè)ReplicaManager實(shí)例對(duì)象,他是會(huì)一直被Kafka的靜態(tài)變量引用的,然后會(huì)一直駐留在Java堆內(nèi)存里,是不會(huì)被垃圾回收掉的。

因?yàn)檫@個(gè)實(shí)例對(duì)象他需要長(zhǎng)期被使用,周期新的被調(diào)用load()方法,所以他就成為了一個(gè)長(zhǎng)時(shí)間存在的對(duì)象。

那么類(lèi)似這種被類(lèi)的靜態(tài)變量長(zhǎng)期引用的對(duì)象,他需要長(zhǎng)期停留在Java堆內(nèi)存里,這這種對(duì)象就是生存周期很長(zhǎng)的對(duì)象,他是輕易不會(huì)被垃圾回收的,他需要長(zhǎng)期存在,不停的去使用他。


4、JVM分代模型:年輕代和老年代

接下來(lái)就要進(jìn)入今天的核心主題了,就是JVM的分代模型,年輕代和老年代。

現(xiàn)在大家已經(jīng)看到,其實(shí)根據(jù)你寫(xiě)代碼方式的不同,采用不同的方式來(lái)創(chuàng)建和使用對(duì)象,其實(shí)對(duì)象的生存周期是不同的。

所以JVM將Java堆內(nèi)存劃分為了兩個(gè)區(qū)域,一個(gè)是年輕代,一個(gè)是老年代。

其中年輕代,顧名思義,就是把第一種代碼示例中的那種,創(chuàng)建和使用完之后立馬就要回收的對(duì)象放在里面

然后老年代呢,就是把第二種代碼示例中的那種,創(chuàng)建之后需要一直長(zhǎng)期存在的對(duì)象放在里面,大家看下圖:

比如下面的代碼,我們?cè)俅蝸?lái)改造一下,再結(jié)合圖,大家會(huì)看的更加的明確一些。

上面那段代碼稍微復(fù)雜了點(diǎn),我們解釋一下

Kafka的靜態(tài)變量“fetcher”引用了ReplicaFetcher對(duì)象,這是長(zhǎng)期需要駐留在內(nèi)存里使用的

這個(gè)對(duì)象會(huì)在年輕代里停留一會(huì)兒,但是最終會(huì)進(jìn)入老年代,大家看下圖。

進(jìn)入main()方法之后,會(huì)先調(diào)用loadReplicasFromDisk()方法,業(yè)務(wù)含義是系統(tǒng)啟動(dòng)就從磁盤(pán)加載一次副本數(shù)據(jù),這個(gè)方法的棧幀會(huì)入棧

然后在這個(gè)方法里面創(chuàng)建了一個(gè)ReplicaManager對(duì)象,這個(gè)對(duì)象他是用完就會(huì)回收,所以是會(huì)放在年輕代里的,由棧幀里的局部變量來(lái)引用

此時(shí)對(duì)應(yīng)著下圖:

然后一旦loadReplicasFromDisk()方法執(zhí)行完畢了,方法的棧幀就會(huì)出棧,對(duì)應(yīng)的年輕代里的ReplicaManager對(duì)象也會(huì)被回收掉,如下圖:

但是接著會(huì)執(zhí)行一段while循環(huán)代碼,他會(huì)周期性的調(diào)用ReplicaFetcher的fetch()方法,去從遠(yuǎn)程加載副本數(shù)據(jù)。

所以ReplicaFetcher這個(gè)對(duì)象因?yàn)楸籏afka類(lèi)的靜態(tài)變量fetcher給引用了,所以他會(huì)長(zhǎng)期存在于老年代里的,持續(xù)被使用。


5、為什么要分成年輕代和老年代?

相信看完這篇文章,大家就一定看明白了,什么樣的對(duì)象是短期存活的對(duì)象,什么樣的對(duì)象是長(zhǎng)期存在的對(duì)象,然后如何分別存在于年輕代和老年代里。

那么為什么需要這么區(qū)分呢?

因?yàn)檫@跟垃圾回收有關(guān),對(duì)于年輕代里的對(duì)象,他們的特點(diǎn)是創(chuàng)建之后很快就會(huì)被回收,所以需要用一種垃圾回收算法

對(duì)于老年代里的對(duì)象,他們的特點(diǎn)是需要長(zhǎng)期存在,所以需要另外一種垃圾回收算法,所以需要分成兩個(gè)區(qū)域來(lái)放不同的對(duì)象。

很多人又會(huì)問(wèn)了,你不是說(shuō)“ReplicaFetcher”這個(gè)長(zhǎng)期存在的對(duì)象,剛開(kāi)始也在年輕代,后來(lái)才會(huì)進(jìn)入老年代么?那他到底什么時(shí)候進(jìn)入老年代?

別急,明天的文章就會(huì)分析這塊。

然后還有人還會(huì)問(wèn)了,那么年輕代和老年代分別怎么進(jìn)行垃圾回收呢?

別急,下周的文章會(huì)主要分析垃圾回收這塊的原理。這周我們主要關(guān)注JVM的內(nèi)存劃分的細(xì)節(jié),搞明白對(duì)象是如何在不同的內(nèi)存區(qū)域里分配的就可以了,學(xué)習(xí)要循序漸進(jìn)。


6、什么是永久代?

很簡(jiǎn)單,JVM里的永久代其實(shí)就是我們之前說(shuō)的方法區(qū)

上面那個(gè)圖里的方法區(qū),其實(shí)就是所謂的永久代,你可以認(rèn)為永久代就是放一些類(lèi)信息的。

這個(gè)話題現(xiàn)在不用過(guò)多考慮,后續(xù)涉及到的時(shí)候,我們會(huì)講到的。


7、上周思考題解答

上周留了一個(gè)思考題,讓大家思考方法區(qū)內(nèi)會(huì)不會(huì)進(jìn)行垃圾回收

其實(shí)有同學(xué)都回答了,非常的好,在以下幾種情況下,方法區(qū)里的類(lèi)會(huì)被回收。

  • 首先該類(lèi)的所有實(shí)例對(duì)象都已經(jīng)從Java堆內(nèi)存里被回收

  • 其次加載這個(gè)類(lèi)的ClassLoader已經(jīng)被回收

  • 最后,對(duì)該類(lèi)的Class對(duì)象沒(méi)有任何引用

滿足上面三個(gè)條件就可以回收該類(lèi)了。


8、今日思考題

給大家出一個(gè)腦筋急轉(zhuǎn)彎,出題思路有點(diǎn)偏:每個(gè)線程都有Java虛擬機(jī)棧,里面也有方法的局部變量等數(shù)據(jù),這個(gè)Java虛擬機(jī)棧需要進(jìn)行垃圾回收嗎?為什么?

End


版權(quán):公眾號(hào)儒猿技術(shù)窩

未經(jīng)許可不得傳播,如有侵權(quán)將追究法律責(zé)任如何

008、聊聊JVM分代模型:年輕代、老年代、永久代的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
黄石市| 忻州市| 集贤县| 迁西县| 婺源县| 佛山市| 云南省| 金沙县| 惠东县| 尼木县| 英山县| 凤山县| 麻江县| 浮梁县| 高邑县| 定襄县| 赤城县| 金平| 宁波市| 花莲县| 安岳县| 商水县| 湘潭市| 红安县| 长沙县| 华安县| 南木林县| 永丰县| 白河县| 峡江县| 林周县| 仲巴县| 武川县| 阿图什市| 宁海县| 兴文县| 酉阳| 广德县| 华容县| 额济纳旗| 合阳县|