日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

jvm性能调优 - 05对象在JVM内存中的分配和流转

發布時間:2025/3/21 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jvm性能调优 - 05对象在JVM内存中的分配和流转 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 前文回顧
  • 大部分正常對象都優先在新生代分配內存
  • 到底什么情況下會觸發新生代的垃圾回收?
  • 長期存活的對象會躲過多次垃圾回收?
  • 老年代會垃圾回收嗎?
  • 關于新生代和老年代的對象分配,這就完了嗎?


前文回顧

經過上一篇文章鋪墊了一些對象分配的基礎知識后,想必大家現在都心里非常有數了,咱們平時代碼里創建出來的對象,一般就是兩種:

  • 一種是短期存活的,分配在Java堆內存之后,迅速使用完就會被垃圾回收

  • 另外一種是長期存活的,需要一直生存在Java堆內存里,讓程序后續不停的去使用

第一種短期存活的對象,是在Java堆內存的新生代里的。第二種長期存活的對象,是在Java堆內存的老年代里的。這個結論,想必大家都已經理解了

好,那么接下來我們就來聊聊,對象到底什么時候進入新生代?然后什么情況下會進入老年代?


大部分正常對象都優先在新生代分配內存

首先我們先來看上篇文章中的一段代碼,稍微帶著大家來理解一個概念:大部分的正常對象,都是優先在新生代分配內存的。

雖然我們看代碼知道,類靜態變量“fetcher”引用的那個“ReplicaFetcher”對象,是會長期存活在內存里的

但是哪怕是這種對象,其實剛開始你通過“new ReplicaFetcher()”代碼來實例化一個對象時,他也是分配在新生代里的。

包括在“loadReplicasFromDisk()”方法中創建的“ReplicaManager”實例對象,也都是一樣分配在新生代里的

同樣,我們以一張圖,來展示一下:


到底什么情況下會觸發新生代的垃圾回收?

現在咱們來假設一個場景,大家應該都知道,一旦“loadReplicasFromDisk()”方法執行完畢之后,這個方法的棧幀出棧,會導致沒有任何局部變量引用那個“ReplicaManager”實例對象了。

此時可能會如下圖所示:

那么此時就一定會立即發生垃圾回收,去回收掉Java堆內存里那個沒人使用的“ReplicaManager”實例對象嗎?

NO

大家別想的那么簡單了,實際上垃圾回收他也得有點觸發的條件。

其中一個比較常見的場景可能是這樣的,假設我們寫的代碼中創建了N多對象,然后導致Java堆內存里囤積了大量的對象。

然后這些對象都是之前有人引用,比如各種各樣的方法中的局部變量,但是現在也都沒人引用了。

如下圖所示

這個時候,如果新生代我們預先分配的內存空間,幾乎都被全部對象給占滿了!此時假設我們代碼繼續運行,他需要在新生代里去分配一個對象,怎么辦?發現新生代里內存空間都不夠了!

這個時候,就會觸發一次新生代內存空間的垃圾回收,新生代內存空間的垃圾回收,也稱之為“Minor GC”,有的時候我們也叫“Young GC”,他會嘗試把新生代里那些沒有人引用的垃圾對象,都給回收掉。

比如上圖中,那個“ReplicaManager”實例對象,其實就是沒有人引用的垃圾對象

此時就會當機立斷,把“ReplicaManager”實例對象給回收掉,騰出更多的內存空間,然后放一個新的對象到新生代里去。

包括上圖中那大量的實例對象,其實也都沒人引用,在這個新生代垃圾回收的過程中,就會把這些垃圾對象也都回收掉。

其實話說回來,大家自己仔細回憶一下,我們在代碼中創建的大部分對象,其實都是這種使用之后立馬就可以回收掉的生存周期極短的對象,是不是?

可能我們會在新生代里分配大量的對象,但是使用完之后立馬就沒人引用了,此時新生代差不多滿了

然后要分配新的對象的時候,發現新生代內存空間不足,就會觸發一次垃圾回收,然后就把所有垃圾對象給干掉,騰出大量的內存空間

如下圖所示:


長期存活的對象會躲過多次垃圾回收?

接著我們來看下一個問題,上圖中大家都注意到了“ReplicaFetcher”實例對象,他是一個長期被“Kafka”類的靜態變量“fetcher”引用的長期存活的對象。

所以雖然你的新生代可能隨著系統的運行,不停的創建對象,然后讓新生代變滿,接著垃圾回收一次,大量對象被回收掉

但是你的這個“ReplicaFetcher”對象,他確是一直會存活在新生代里的。

因為他一直被“Kafka”類的靜態變量給引用了,所以他不會被回收。那么此時JVM就有一條規定了

如果一個實例對象在新生代中,成功的在15次垃圾回收之后,還是沒被回收掉,就說明他已經15歲了。

這是對象的年齡,每垃圾回收一次,如果一個對象沒被回收掉,他的年齡就會增加1。

所以如果上圖中的那個“ReplicaFetcher”對象在新生代中成功躲過10多次垃圾回收,成為一個“老年人”,那么就會被認為是會長期存活在內存里的對象。

然后他會被轉移到Java堆內存的老年代中去,顧名思義,老年代就是放這些年齡很大的對象。

我們再來看一張圖:


老年代會垃圾回收嗎?

接著下一個問題就是,老年代里的那些對象會被垃圾回收嗎?

答案是肯定的,因為老年代里的對象也有可能隨著代碼的運行,不再被任何人引用了,就需要被垃圾回收。

大家可以思考一下,如果隨著類似上面的情況,越來越多的對象進入老年代,一旦老年代也滿了,是不是就要對老年代垃圾回收了?

沒錯,這是肯定的,但是暫時我們先不用過多的去考慮這里的細節,后面我們會進行深入剖析。


關于新生代和老年代的對象分配,這就完了嗎?

還有人會說,關于新生代和老年代的對象分配,這就結束了嗎?

當然不是,我們這里僅僅是相較于之前的文章,更進一步給大家分析了一下對象分配的一些機制。

但是其實在對象分配這塊,還有很多其他的復雜機制,比如:

  • 新生代垃圾回收之后,因為存活對象太多,導致大量對象直接進入老年代

  • 特別大的超大對象直接不經過新生代就進入老年代

  • 動態對象年齡判斷機制

  • 空間擔保機制

這部分內容結合案例,結合真實生產問題,把JVM各種底層細節帶出來。

到這里 ,大家對對象內存分配,了解到這個程度就行了,給大家總結一下:

  • 先理解對象優先分配在新生代

  • 新生代如果對象滿了,會觸發Minor GC回收掉沒有人引用的垃圾對象

  • 如果有對象躲過了十多次垃圾回收,就會放入老年代里

  • 如果老年代也滿了,那么也會觸發垃圾回收,把老年代里沒人引用的垃圾對象清理掉

總結

以上是生活随笔為你收集整理的jvm性能调优 - 05对象在JVM内存中的分配和流转的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。