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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

JVM对象内存分配机制之对象在Eden区分配(五)

發布時間:2023/12/20 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM对象内存分配机制之对象在Eden区分配(五) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

JVM對象內存分配機制之對象在Eden區分配

  • 前言
  • 一、對象在Eden區分配
  • 二、大對象直接進入老年代
  • 三、長期存活的對象將進入老年代
  • 四、老年代空間分配擔保機制


前言

上篇文章解釋了對象在棧上分配的相關內容,這篇是上一篇的后續,解釋一下對象在Eden區分配,以及上一篇內存分配流程圖中大對象和長期存活的對象該何去何從。


一、對象在Eden區分配

大多數情況下,對象在新生代中 Eden 區分配。當 Eden 區沒有足夠空間進行分配時,虛擬機將發起一次Minor GC。我 們來進行實際測試一下。

在測試之前我們先來看看 Minor GC和Full GC 有什么不同呢?

Minor GC/Young GC:指發生新生代的的垃圾收集動作,Minor GC非常頻繁,回收速度一般也比較快。

Major GC/Full GC:一般會回收老年代 ,年輕代,方法區的垃圾,Major GC的速度一般會比Minor GC的慢 10倍以上。

Eden與Survivor區默認8:1:1

大量的對象被分配在eden區,eden區滿了后會觸發minor gc,可能會有99%以上的對象成為垃圾被回收掉,剩余存活 的對象會被挪到為空的那塊survivor區,下一次eden區滿了后又會觸發minor gc,把eden區和survivor區垃圾對象回 收,把剩余存活的對象一次性挪動到另外一塊為空的survivor區,因為新生代的對象都是朝生夕死的,存活時間很短,所 以JVM默認的8:1:1的比例是很合適的,讓eden區盡量的大,survivor區夠用即可, JVM默認有這個參數-XX:+UseAdaptiveSizePolicy(默認開啟),會導致這個8:1:1比例自動變化,如果不想這個比例有變 化可以設置參數-XX:-UseAdaptiveSizePolicy

package com.daydayup.jvm;/*** 添加運行JVM參數:-XX:+PrintGCDetails*/ public class GCTest {public static void main(String[] args) throws InterruptedException {byte[] allocation1, allocation2/*, allocation3, allocation4, allocation5, allocation6*/;allocation1 = new byte[60000*1024]; // allocation2 = new byte[8000*1024]; // allocation3 = new byte[1000*1024]; // allocation4 = new byte[1000*1024]; // allocation5 = new byte[1000*1024]; // allocation6 = new byte[1000*1024];} } //運行結果[GC (Allocation Failure) [PSYoungGen: 65024K->904K(75776K)] 65024K->912K(249344K), 0.0006997 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] HeapPSYoungGen total 75776K, used 2204K [0x000000076bd00000, 0x0000000771180000, 0x00000007c0000000)eden space 65024K, 2% used [0x000000076bd00000,0x000000076be45378,0x000000076fc80000)from space 10752K, 8% used [0x000000076fc80000,0x000000076fd62020,0x0000000770700000)to space 10752K, 0% used [0x0000000770700000,0x0000000770700000,0x0000000771180000)ParOldGen total 173568K, used 8K [0x00000006c3600000, 0x00000006cdf80000, 0x000000076bd00000)object space 173568K, 0% used [0x00000006c3600000,0x00000006c3602000,0x00000006cdf80000)Metaspace used 3221K, capacity 4496K, committed 4864K, reserved 1056768Kclass space used 350K, capacity 388K, committed 512K, reserved 1048576K

我們可以看出eden區內存幾乎已經被分配完全(即使程序什么也不做,新生代也會使用至少幾M內存)。假如我們再為 allocation2分配內存會出現什么情況呢?

package com.daydayup.jvm;/*** 添加運行JVM參數:-XX:+PrintGCDetails*/ public class GCTest {public static void main(String[] args) throws InterruptedException {byte[] allocation1, allocation2/*, allocation3, allocation4, allocation5, allocation6*/;allocation1 = new byte[60000*1024];allocation2 = new byte[8000*1024]; // allocation3 = new byte[1000*1024]; // allocation4 = new byte[1000*1024]; // allocation5 = new byte[1000*1024]; // allocation6 = new byte[1000*1024];} }//運行結果[GC (Allocation Failure) [PSYoungGen: 65024K->920K(75776K)] 65024K->60928K(249344K), 0.0243280 secs] [Times: user=0.14 sys=0.00, real=0.02 secs] HeapPSYoungGen total 75776K, used 9570K [0x000000076bd00000, 0x0000000775100000, 0x00000007c0000000)eden space 65024K, 13% used [0x000000076bd00000,0x000000076c572a78,0x000000076fc80000)from space 10752K, 8% used [0x000000076fc80000,0x000000076fd66030,0x0000000770700000)to space 10752K, 0% used [0x0000000774680000,0x0000000774680000,0x0000000775100000)ParOldGen total 173568K, used 60008K [0x00000006c3600000, 0x00000006cdf80000, 0x000000076bd00000)object space 173568K, 34% used [0x00000006c3600000,0x00000006c709a010,0x00000006cdf80000)Metaspace used 3221K, capacity 4496K, committed 4864K, reserved 1056768Kclass space used 350K, capacity 388K, committed 512K, reserved 1048576K

簡單解釋一下為什么會出現這種情況: 因為給allocation2分配內存的時候eden區內存幾乎已經被分配完了,我們剛剛講 了當Eden區沒有足夠空間進行分配時,虛擬機將發起一次Minor GC,GC期間虛擬機又發現allocation1無法存入 Survior空間,所以只好把新生代的對象提前轉移到老年代中去,老年代上的空間足夠存放allocation1,所以不會出現 Full GC。執行Minor GC后,后面分配的對象如果能夠存在eden區的話,還是會在eden區分配內存。

package com.daydayup.jvm;/*** 添加運行JVM參數:-XX:+PrintGCDetails*/ public class GCTest {public static void main(String[] args) throws InterruptedException {byte[] allocation1, allocation2, allocation3, allocation4, allocation5, allocation6;allocation1 = new byte[60000*1024];allocation2 = new byte[8000*1024];allocation3 = new byte[1000*1024];allocation4 = new byte[1000*1024];allocation5 = new byte[1000*1024];allocation6 = new byte[1000*1024];} }//運行結果[GC (Allocation Failure) [PSYoungGen: 65024K->872K(75776K)] 65024K->60880K(249344K), 0.0233776 secs] [Times: user=0.00 sys=0.02, real=0.02 secs] HeapPSYoungGen total 75776K, used 13785K [0x000000076bd00000, 0x0000000775100000, 0x00000007c0000000)eden space 65024K, 19% used [0x000000076bd00000,0x000000076c99c798,0x000000076fc80000)from space 10752K, 8% used [0x000000076fc80000,0x000000076fd5a020,0x0000000770700000)to space 10752K, 0% used [0x0000000774680000,0x0000000774680000,0x0000000775100000)ParOldGen total 173568K, used 60008K [0x00000006c3600000, 0x00000006cdf80000, 0x000000076bd00000)object space 173568K, 34% used [0x00000006c3600000,0x00000006c709a010,0x00000006cdf80000)Metaspace used 3221K, capacity 4496K, committed 4864K, reserved 1056768Kclass space used 350K, capacity 388K, committed 512K, reserved 1048576K

二、大對象直接進入老年代

大對象就是需要大量連續內存空間的對象(比如:字符串、數組)。JVM參數 -XX:PretenureSizeThreshold 可以設置大對象的大小,如果對象超過設置大小會直接進入老年代,不會進入年輕代,這個參數只在 Serial 和ParNew兩個收集器下 有效。比如設置JVM參數:-XX:PretenureSizeThreshold=1000000 (單位是字節) -XX:+UseSerialGC ,再執行下上面的第一 個程序會發現大對象直接進了老年代 。

原因是為了避免為大對象分配內存時的復制操作而降低效率。

三、長期存活的對象將進入老年代

既然虛擬機采用了分代收集的思想來管理內存,那么內存回收時就必須能識別哪些對象應放在新生代,哪些對象應放在 老年代中。為了做到這一點,虛擬機給每個對象一個對象年齡(Age)計數器。
如果對象在 Eden 出生并經過第一次 Minor GC 后仍然能夠存活,并且能被 Survivor 容納的話,將被移動到 Survivor 空間中,并將對象年齡設為1。對象在 Survivor 中每熬過一次 MinorGC,年齡就增加1歲,當它的年齡增加到一定程度(默認為15歲,CMS收集器默認6歲,不同的垃圾收集器會略微有點不同),就會被晉升到老年代中。對象晉升到老年代 的年齡閾值,可以通過參數 -XX:MaxTenuringThreshold 來設置。

四、老年代空間分配擔保機制

年輕代每次minor gc之前JVM都會計算下老年代剩余可用空間 ,如果這個可用空間小于年輕代里現有的所有對象大小之和(包括垃圾對象) 就會看一個“-XX:-HandlePromotionFailure”(jdk1.8默認就設置了)的參數是否設置了, 如果有這個參數,就會看看老年代的可用內存大小,是否大于之前每一次minor gc后進入老年代的對象的平均大小

如果上一步結果是小于或者之前說的參數沒有設置,那么就會觸發一次Full gc,對老年代和年輕代一起回收一次垃圾, 如果回收完還是沒有足夠空間存放新的對象就會發生"OOM" 當然,如果minor gc之后剩余存活的需要挪動到老年代的對象大小還是大于老年代可用空間,那么也會觸發full gc,full gc完之后如果還是沒有空間放minor gc之后的存活對象,則也會發生“OOM”。

下面附擔保機制的流程圖:

總結

以上是生活随笔為你收集整理的JVM对象内存分配机制之对象在Eden区分配(五)的全部內容,希望文章能夠幫你解決所遇到的問題。

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