Hotspot中Java Heap的构成与创建

  • 1. JavaHeap 的构成

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 信息,常量池等等一些信息。

 

  • 2.Java Heap Hotspot 中是如何创建、分配的

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

 

  • 3. 总结

      JVM 会根据传进来的参数选择 gc 算法, gc 算法确定后, CollectorPolicy 就会确定了,确定完 collectorpolicy 就能知道 GenerationSpec ,然后创建 GenCollectedHeap ,根据 GenerationSpec 初始化 JavaHeap 中的 YoungGen,OldGen,PermGen

你可能感兴趣的:(JVM)