Java Heap 包含三个部分 YoungGen,OldGen,PermGen 三个部分,亦叫作年轻代,年老代,永久代。
DefNewGeneration 是 YoungGen 的一个实现,包含 _eden_space, _from_space, _to_space 三个部分。在 YoungGen 中分配对象的时候会在 eden 中进行分配, from 和 to 是在 ygc 的过程中用到的,将 eden 和 from 中存活的对象拷贝到 to 中,每一次ygc,from和to的角色会对调一下
ConcurrentMarkSweepGeneration 是 OldGen 的一个实现,这里存储的是经过 ygc 后, age 较大的对象,或者是很大的对象 ( 在 Young Gen 中分配不了的 ) ,或者是 ygc 的时候 to 的区域受限存不了的对象也会晋升到 OldGen 中
PermGen 是存储 class 信息,常量池等等一些信息。
Java Heap 的创建经过下面几层路径,层层下去,最终完成创建,分配。
Thread.cpp,Create_VM -> Arguments::parse -> init_globals() -> universe_init() -> Universe::initialize_heap()
在上面的路径中,在 JVM 初始化阶段,会先分析传进来的 java 参数,将一些变量进行修改或者初始化。
从 Universe::initialize_heap() 开始创建、分配 java heap 。
2.1 创建 CollectorPolicy
这里根据传进来的参数,创建合适的 CollectorPolicy ,即给相应的 Generation ,包括 YoungGen,OldGen,PermGen 设置好相应的描述参数,最终会创建 GenerationSpec 来描述每一个 Generation ,根据 GenerationSpec 去创建 Generatiion 。
在 Universe::initialize_heap() 函数中有下面的代码
if (UseParallelGC) {
#ifndef SERIALGC
Universe::_collectedHeap = new ParallelScavengeHeap();
#else // SERIALGC
fatal("UseParallelGC not supported in java kernel vm.");
#endif // SERIALGC
} else if (UseG1GC) {
#ifndef SERIALGC
G1CollectorPolicy* g1p = new G1CollectorPolicy_BestRegionsFirst();
G1CollectedHeap* g1h = new G1CollectedHeap(g1p);
Universe::_collectedHeap = g1h;
#else // SERIALGC
fatal("UseG1GC not supported in java kernel vm.");
#endif // SERIALGC
} else {
GenCollectorPolicy *gc_policy;
if (UseSerialGC) {
gc_policy = new MarkSweepPolicy();
} else if (UseConcMarkSweepGC) {
#ifndef SERIALGC
if (UseAdaptiveSizePolicy) {
gc_policy = new ASConcurrentMarkSweepPolicy();
} else {
gc_policy = new ConcurrentMarkSweepPolicy();
}
#else // SERIALGC
fatal("UseConcMarkSweepGC not supported in java kernel vm.");
#endif // SERIALGC
} else { // default old generation
gc_policy = new MarkSweepPolicy();
}
Universe::_collectedHeap = new GenCollectedHeap(gc_policy);
}
从这段代码中可以看出,根据一些参数的值,例如 UseConcMarkSweepGC 、 UseSerialGC 、 UseParallelGC 等等,选择何种 gc 策略,进而选择使用什么样的 heap 。
以 ParNew 和 Cms 为例来说,会执行到 gc_policy = new ConcurrentMarkSweepPolicy(); 这一句, ConcurrentMarkSweepPolicy 的继承关系结构如下
class ConcurrentMarkSweepPolicy : public TwoGenerationCollectorPolicy {
class TwoGenerationCollectorPolicy : public GenCollectorPolicy {
class GenCollectorPolicy : public CollectorPolicy {
class CollectorPolicy : public CHeapObj {
protected:
size_t _initial_heap_byte_size;
size_t _max_heap_byte_size;
size_t _min_heap_byte_size;
size_t _min_alignment;
size_t _max_alignment;
}
在 ConcurrentMarkSweepPolicy 的构造函数中,会执行下面一些操作。构造函数执行的次序如下。
1.CollectorPolicy ,简单初始化一些参数
_min_alignment(1),
_max_alignment(1),
_initial_heap_byte_size(0),
_max_heap_byte_size(0),
_min_heap_byte_size(0),
2.GenCollectorPolicy ,默认构造
3.TwoGenerationCollectorPolicy ,默认构造
4.ConcurrentMarkSweepPolicy 调用了 initialize_all()
initialize_all();GenCollectorPolicy 的虚函数
virtual void initialize_all() {
initialize_flags();
initialize_size_info();
initialize_generations();
}
接下来分析上面提到的三个初始化函数。
1.initialize_flags()
// 设置调整jvm 参数的值,实际上也就是PermGen的一些参数,CollectorPolicy methods,包括MaxPermSize,PermSize,SharedReadOnlySize,SharedReadWriteSize,SharedMiscDataSize
void CollectorPolicy::initialize_flags() {
// 设置调整jvm 参数的值,包括NewSize,MaxNewSize,SurvivorRatio
void GenCollectorPolicy::initialize_flags() {
// 设置最小对齐65536=64k
set_min_alignment((uintx) Generation::GenGrain);
// 设置最大对齐card_size * os::vm_page
set_max_alignment(compute_max_alignment());
}
/// 设置调整jvm 参数的值,包括OldSize,MaxHeapSize
TwoGenerationCollectorPolicy::initialize_flags
2.initialize_size_info();
//设置_initial_heap_byte_size,_max_heap_byte_size,_min_heap_byte_size
CollectorPolicy::initialize_size_info(){
}
//设置gen[0]
GenCollectorPolicy::initialize_size_info(){
set_min_gen0_size(max_new_size);
set_initial_gen0_size(max_new_size);
set_max_gen0_size(max_new_size);
}
//设置gen[1], _min_gen1_size, _max_gen1_size, _initial_gen1_size
TwoGenerationCollectorPolicy::initialize_size_info(){
}
3.initialize_generations();
ConcurrentMarkSweepPolicy::initialize_generations(){
CollectorPolicy::initialize_perm_generation(),初始化PermGenSpec
_generations = new GenerationSpecPtr[number_of_generations()];//分代,为2
//ParNewGen::in_user()
_generations[0] = new GenerationSpec(Generation::ParNew,
_initial_gen0_size, _max_gen0_size);
_generations[1] = new GenerationSpec(Generation::ConcurrentMarkSweep,
_initial_gen1_size, _max_gen1_size);
//NewGen ,OldGen, PermGen
//NewGen+OldGen = MaxHeapSize
New GenCollectedHeap();初始化gc的workgroup WorkGang
}
2.2 创建 GenCollectedHeap
在创建完 CollectorPolicy 之后,会创建 GenCollectedHeap 。在创建 GenCollectedHeap 中,没有进行真正分配空间,只是初始化了一些参数而已,真正的分配空间是在 Universe::heap()->initialize() 中进行的。
3.2Java Heap 分配
创建 GenCollectedHeap 后,会有初始化的代码, Universe::heap()->initialize(); 这里调用了 GenCollectedHeap::initialize() ,主要代码及注释如下所示。
{
//分配区域,由heap_rs保存,三个区域:YoungGen,OldGen,PermGen
heap_address = allocate(alignment, perm_gen_spec, &n_covered_regions,
&n_covered_regions, &heap_rs);
//_reserved区域包括Y,O,P三个区域
_reserved = MemRegion((HeapWord*)heap_rs.base(),
(HeapWord*)(heap_rs.base() + heap_rs.size()));
_reserved.set_word_size(0);
_reserved.set_start((HeapWord*)heap_rs.base());
size_t actual_heap_size = heap_rs.size() - perm_gen_spec->misc_data_size()
- perm_gen_spec->misc_code_size();
_reserved.set_end((HeapWord*)(heap_rs.base() + actual_heap_size));
//_rem_set管理的_reserved区域为分配的整体内存,包括三个部分Y,O,P
_rem_set = collector_policy()->create_rem_set(_reserved, n_covered_regions);
set_barrier_set(rem_set()->bs());
//将_reserved区域划分到对应的二个Y,O区域,并init
for (i = 0; i < _n_gens; i++) {
ReservedSpace this_rs = heap_rs.first_part(_gen_specs[i]->max_size(),
UseSharedSpaces, UseSharedSpaces);
_gens[i] = _gen_specs[i]->init(this_rs, i, rem_set());
heap_rs = heap_rs.last_part(_gen_specs[i]->max_size());
}
//划分剩余的区域到perm gen,并init
_perm_gen = perm_gen_spec->init(heap_rs, PermSize, rem_set());
}
从代码中看出,这里是根据之前的 generationspec ,通过 allocate 函数分配出空间,包括 YoungGen,OldGen,PermGen ,然后保存在 _reserved 中, _reserved 会设置实际的 heap 空间为去掉 PermGen 中的 msic_data 和 msic_code 的空间;接下来会创建一个 BarrierSet ,这是一个覆盖整个 _reserved 实际空间的数组,数组中每个 byte 对应 heap 中的 512B( 根据 BarrierSet 中常量设置有关 ) ;最后会依次初始化 YoungGen,OldGen,PermGen 。
JVM 会根据传进来的参数选择 gc 算法, gc 算法确定后, CollectorPolicy 就会确定了,确定完 collectorpolicy 就能知道 GenerationSpec ,然后创建 GenCollectedHeap ,根据 GenerationSpec 初始化 JavaHeap 中的 YoungGen,OldGen,PermGen 。