天天看點

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

java堆是被所有線程共享的一塊記憶體區域,所有對象和數組都在堆上進行記憶體配置設定。為了進行高效的垃圾回收,虛拟機把堆記憶體劃分成新生代、老年代和永久代(1.8中無永久代,使用metaspace實作)三塊區域。

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

java把記憶體分成兩種:棧記憶體和堆記憶體。關于堆記憶體和棧記憶體的差別與聯系。簡單的來講,堆記憶體用于存放由new建立的對象和數組,在堆中配置設定的記憶體,由java虛拟機自動垃圾回收器來管理。而棧記憶體由使用的人向系統申請,申請人進行管理。

java中配置設定堆記憶體是自動初始化的,其入口位于universe::initialize_heap方法中,相關代碼如下:

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

其中useparallelgc、useg1gc、useconcmarksweepgc都可以通過啟動參數進行設定,整個初始化過程分成三步:

1、初始化gc政策;

2、初始化分代生成器;

3、初始化java堆管理器;

hotspot的gc政策實作如下:

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

其中marksweeppolicy是基于标記-清除思想的gc政策,如果虛拟機啟動參數沒有指定gc算法,則使用預設使用useserialgc,以asconcurrentmarksweeppolicy政策為例,對gc政策的初始化過程進行分析:

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

調用父類concurrentmarksweeppolicy構造方法,其中initialize_all定義在gencollectorpolicy中,相關代碼如下:

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

負責對新生代、老年代以及永久代設定的記憶體大小進行調整。

由collectorpolicy::initialize_flags實作,永久代的初始值預設為4m,最大值為64m,可以通過參數-xx:permsize和-xx:maxpermsize進行重新設定。代碼如下:

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

由gencollectorpolicy::initialize_flags實作:

1、新生代的初始值newsize預設為1m,最大值需要設定,可以通過參數-xx:newsize和-xx:maxnewsize或-xmn進行設定;

2、newratio為老年代與新生代的大小比值,預設為2;

3、survivorratio為新生代中eden和survivor的大小比值,預設為8;

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

由twogenerationcollectorpolicy::initialize_flags實作

1、老年代的初始值oldsize預設為4m,可以通過參數-xx:oldsize進行設定;

2、最大堆大小maxheapsize預設為96m,可以通過參數-xmx進行設定;

3、如果設定的新生代和老年代的記憶體容量大于maxheapsize,則重新設定maxheapsize;

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

設定新生代、老年代以及永久代的容量,包括初始值、最小值和最大值

其中initialheapsize和arguments::min_heap_size()可以通過參數-xms進行設定。

1、設定初始堆容量_initial_heap_byte_size;

2、設定最小堆容量_min_heap_byte_size;

3、設定最大堆容量_max_heap_byte_size;

相關代碼如下:

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化
深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

1、如果maxnewsize重新設定過,即設定-xmn參數,則根據不同情況設定max_new_size;

2、否則通過scale_by_newratio_aligned方法根據newratio和_max_heap_byte_size重新計算max_new_size值,其中newratio預設為2,表示新生代的大小占整個堆的1/3;

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

3、如果最大堆_max_heap_byte_size等于最小堆_min_heap_byte_size,則設定新生代的初始值、最小值和最大值為max_new_size,否則執行下一步。

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

4、如果newsize重新設定過,即設定了-xmn參數,則使用newsize設定_min_gen0_size,否則使用scale_by_newratio_aligned方法重新計算新生代最小值和初始值,實作如下:

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

1、如果參數沒有設定oldsize,則使用min_heap_byte_size() - min_gen0_size(),即最小堆大小和新生代最小值之差設定老年代最小值,初始值類似;

2、否則根據設定的oldsize,通過adjust_gen0_sizes方法重新設定新生代的最小值和初始值;

分代生成器儲存了各個記憶體代的初始值和最大值,新生代和老年代通過generationspec實作,永久代通過permanentgenerationspec實作。

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

每個生成器generationspec執行個體儲存目前分代的gc算法、記憶體的初始值和最大值。

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

除了generationspec執行個體中的資料,如果設定usesharedspaces和dumpsharedspaces,還需要儲存額外的資料。concurrentmarksweeppolicy::initialize_generations方法實作了分代生成器的初始化,實作如下:

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

gencollectedheap是整個java堆的管理器,負責java對象的記憶體配置設定和垃圾對象的回收,通過initialize方法進行初始化,相關代碼如下:

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

1、通過gc政策的number_of_generations方法擷取分代數量,如果使用asconcurrentmarksweeppolicy,預設分代數為2;

2、通過align方法對齊生成器的初始值和最大值;

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

3、通過allocate為堆申請空間;

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

4、通過分代生成器的init方法為對應的分代配置設定記憶體空間;

深入了解Java之JVM堆記憶體配置設定堆記憶體初始化

5、如果目前的gc政策為concurrentmarksweeppolicy,則通過create_cms_collector建立gc線程。

到此,jvm堆記憶體的完整配置設定流程就分析完了。