Hotspot源码解析-第十七章-虚拟机万物创建(二)

17.2 GC策略初始化

这一步主要就是确定分代(新生代和老年代)信息、即将分配的Java堆内存的大小,以及针对这些信息的校验

17.2.1 collectorPolicy.cpp&ollectorPolicy.hpp

17.2.1.1 initialize_all
virtual void initialize_all() {
    // 针对内存分配的大小值做设置和校验
    CollectorPolicy::initialize_all();
    // 创建并分配新生代和老年代对象的内存
    initialize_generations();
  }

// 对应 CollectorPolicy::initialize_all() 函数
virtual void initialize_all() {
    // 父类中,这是一个纯虚函数(相当于Java里面的抽象函数),只能去子类中找实现,这个函数就是计算即将要创建和分配的内存的对齐值
    initialize_alignments(); 
    // 对 Java堆大小值的判断和设置
    initialize_flags();
    // 对以上两步产生的大小做参数检验
    initialize_size_info();
  }

// 对应 initialize_alignments() 函数
void MarkSweepPolicy::initialize_alignments() {
  /*
  * 设置空间和分代对齐(C/C++中分配内存时都需要按着一定大小对齐),对齐的目的就是为了提高内存访问效率,CPU读取内存时不是一个一个字节读的,而是一批字节来读,比如4字节、8字节和64字节等,具体读多少,与CPU的架构、型号、年份有关,现在的机器基本是读64字节(缓存行大小),如果没按对齐规则对齐,就可能读取到的内存是“半包”,这就需要CPU多次读取,效率较低。这里按Generation::GenGrain对齐,这个值定义在generattion.hpp的枚举中
  enum SomePublicConstants {
    LogOfGenGrain = 16 ARM32_ONLY(+1),  // 最终得出结果16
    GenGrain = 1 << LogOfGenGrain    // 1 << 16  ==> 2^16 ==> 64 * k
  };
  通过上面的定义可知,_space_alignment和_gen_alignment的值最终就是64*k,也就是按这个值来对齐
  */  
  _space_alignment = _gen_alignment = (uintx)Generation::GenGrain;
  _heap_alignment = compute_heap_alignment();   // 计算堆空间的对齐值,最终=512 * 4K
}
// 对应 compute_heap_alignment() 函数
size_t CollectorPolicy::compute_heap_alignment() {
  // 这里就是按CardTable卡表的大小乘以页大小来对齐的,查看源码可以得出,卡表大小card_size=1 << 9 ==> 2^9 ==> 512,最终对齐大小等于:512 * 4K(page_size)
  size_t alignment = GenRemSet::max_alignment_constraint(GenRemSet::CardTable);

  if (UseLargePages) { // 用大页,这种情况,忽略
      alignment = lcm(os::large_page_size(), alignment);
  }

  return alignment;
}

// 对应 initialize_flags() 函数
void CollectorPolicy::initialize_flags() {
  // 检验上一步计算的各空间对齐值不为0  
  assert(_space_alignment != 0, "Space alignment not set up properly");
  assert(_heap_alignment != 0, "Heap alignment not set up properly");
  assert(_heap_alignment >= _space_alignment,
         err_msg("heap_alignment: " SIZE_FORMAT " less than space_alignment: " SIZE_FORMAT,
                 _heap_alignment, _space_alignment));
  assert(_heap_alignment % _space_alignment == 0,
         err_msg("heap_alignment: " SIZE_FORMAT " not aligned by space_alignment: " SIZE_FORMAT,
                 _heap_alignment, _space_alignment));
  // 检查空间大小限制,InitialHeapSize和MaxHeapSize的值在`章节8.1.1.2`中做了解析,有兴趣的,再回头看看
  if (FLAG_IS_CMDLINE(MaxHeapSize)) {
    if (FLAG_IS_CMDLINE(InitialHeapSize) && InitialHeapSize > MaxHeapSize) {
      vm_exit_during_initialization("Initial heap size set to a larger value than the maximum heap size");
    }
    if (_min_heap_byte_size != 0 && MaxHeapSize < _min_heap_byte_size) {
      vm_exit_during_initialization("Incompatible minimum and maximum heap sizes specified");
    }
    _max_heap_size_cmdline = true;
  }

  // 初始堆大小不能小于1M
  if (InitialHeapSize < M) {
    vm_exit_during_initialization("Too small initial heap");
  }
  // 最小堆大小不能小于1M
  if (_min_heap_byte_size < M) {
    vm_exit_during_initialization("Too small minimum heap");
  }

  // 用 用户从 -Xmx and -Xms 设置的值,并通过_heap_alignment的大小对齐,得到最小堆大小、初始堆大小、最大堆大小
  _min_heap_byte_size = align_size_up(_min_heap_byte_size, _heap_alignment);
  uintx aligned_initial_heap_size = align_size_up(InitialHeapSize, _heap_alignment);
  uintx aligned_max_heap_size = align_size_up(MaxHeapSize, _heap_alignment);

  // 值改变了,就写回对应的flags中,这块的设置看`章节8.1.1.3`
  if (aligned_initial_heap_size != InitialHeapSize) {
    FLAG_SET_ERGO(uintx, InitialHeapSize, aligned_initial_heap_size);
  }
  if (aligned_max_heap_size != MaxHeapSize) {
    FLAG_SET_ERGO(uintx, MaxHeapSize, aligned_max_heap_size);
  }

  if (FLAG_IS_CMDLINE(InitialHeapSize) && _min_heap_byte_size != 0 &&
      InitialHeapSize < _min_heap_byte_size) {
    vm_exit_during_initialization("Incompatible minimum and initial heap sizes specified");
  }
  if (!FLAG_IS_DEFAULT(InitialHeapSize) && InitialHeapSize > MaxHeapSize) {
    FLAG_SET_ERGO(uintx, MaxHeapSize, InitialHeapSize);
  } else if (!FLAG_IS_DEFAULT(MaxHeapSize) && InitialHeapSize > MaxHeapSize) {
    FLAG_SET_ERGO(uintx, InitialHeapSize, MaxHeapSize);
    if (InitialHeapSize < _min_heap_byte_size) {
      _min_heap_byte_size = InitialHeapSize;
    }
  }

  _initial_heap_byte_size = InitialHeapSize;
  _max_heap_byte_size = MaxHeapSize;

  FLAG_SET_ERGO(uintx, MinHeapDeltaBytes, align_size_up(MinHeapDeltaBytes, _space_alignment));

  DEBUG_ONLY(CollectorPolicy::assert_flags();)
}

// 分代初始化,默认分成两代(年轻和老年代)
void MarkSweepPolicy::initialize_generations() {
  // 通过malloc() 库函数分配内存,并得到一个大小为2的分代数组,分别存放年轻代和老年代GenerationSpec,number_of_generations() 这个函数里面写死了返回2
  _generations = NEW_C_HEAP_ARRAY3(GenerationSpecPtr, number_of_generations(), mtGC, CURRENT_PC,
    AllocFailStrategy::RETURN_NULL);
  if (_generations == NULL) {
    vm_exit_during_initialization("Unable to allocate gen spec");
  }

  if (UseParNewGC) {
    _generations[0] = new GenerationSpec(Generation::ParNew, _initial_gen0_size, _max_gen0_size);
  } else {
    // 串行GC的,走这条线,创建新生代GenerationSpec对象,对象内存都是通过malloc()来分配的
    _generations[0] = new GenerationSpec(Generation::DefNew, _initial_gen0_size, _max_gen0_size);
  }
  // 创建老年代GenerationSpec对象
  _generations[1] = new GenerationSpec(Generation::MarkSweepCompact, _initial_gen1_size, _max_gen1_size);

  if (_generations[0] == NULL || _generations[1] == NULL) {
    vm_exit_during_initialization("Unable to allocate gen spec");
  }
}


17.3 Java堆空间创建

17.3.1 genCollectedHeap.cpp

17.3.1.1 GenCollectedHeap::GenCollectedHeap
GenCollectedHeap::GenCollectedHeap(GenCollectorPolicy *policy) :
  SharedHeap(policy),  // 先调用父类SharedHeap构造函数,看`章节17.3.1.2`
  _gen_policy(policy), // _gen_policy 赋值为 policy
// 创建一个子任务管理类,管理所有子任务,并赋值给_process_strong_tasks
  _process_strong_tasks(new SubTasksDone(GCH_PS_NumElements)),
  _full_collections_completed(0) // _full_collections_completed 赋值
{
  assert(policy != NULL, "Sanity check");
}

17.3.1.2 sharedHeap.cpp->SharedHeap::SharedHeap
SharedHeap::SharedHeap(CollectorPolicy* policy_) :
  CollectedHeap(), // 继续调用上级构造函数
  _collector_policy(policy_),  // 以下为赋值操作
  _rem_set(NULL),
  _strong_roots_parity(0),
  _workers(NULL)
{
  _sh = this;  // ch is static, should be set only once.
  // 由于我们讨论的是串行的GC收集器,所以下面这个逻辑不会走,忽略
  if ((UseParNewGC ||
      (UseConcMarkSweepGC && (CMSParallelInitialMarkEnabled ||
                              CMSParallelRemarkEnabled)) ||
       UseG1GC) &&
      ParallelGCThreads > 0) {
    _workers = new FlexibleWorkGang("Parallel GC Threads", ParallelGCThreads,
                            /* are_GC_task_threads */true,
                            /* are_ConcurrentGC_threads */false);
    if (_workers == NULL) {
      vm_exit_during_initialization("Failed necessary allocation.");
    } else {
      _workers->initialize_workers();
    }
  }
}
17.3.1.3 collectedHeap.cpp->CollectedHeap::CollectedHeap
CollectedHeap::CollectedHeap() : _n_par_threads(0)  // 赋值
{
  // 下面这几步就是得到最大数组的大小,用于后期判断一个对象最大占用内存大小的限制
  const size_t max_len = size_t(arrayOopDesc::max_array_length(T_INT));
  const size_t elements_per_word = HeapWordSize / sizeof(jint);
  _filler_array_max_size = align_object_size(filler_array_hdr_size() +
                                             max_len / elements_per_word);
  // 以下都是赋初始值操作
  _barrier_set = NULL;
  _is_gc_active = false;
  _total_collections = _total_full_collections = 0;
  _gc_cause = _gc_lastcause = GCCause::_no_gc;
  NOT_PRODUCT(_promotion_failure_alot_count = 0;)
  NOT_PRODUCT(_promotion_failure_alot_gc_number = 0;)

  if (UsePerfData) {  // 有关性能数据的,先忽略,以后有机会再单开一个专题来讲
    EXCEPTION_MARK;

    // create the gc cause jvmstat counters
    _perf_gc_cause = PerfDataManager::create_string_variable(SUN_GC, "cause",
                             80, GCCause::to_string(_gc_cause), CHECK);

    _perf_gc_lastcause =
                PerfDataManager::create_string_variable(SUN_GC, "lastCause",
                             80, GCCause::to_string(_gc_lastcause), CHECK);
  }
  _defer_initial_card_mark = false; // strengthened by subclass in pre_initialize() below.
  // gc日志事件
  if (LogEvents) {
    _gc_heap_log = new GCHeapLog();
  } else {
    _gc_heap_log = NULL;
  }
}

你可能感兴趣的:(Java虚拟机,java)