Hotspot 垃圾回收之ConcurrentMarkSweepGeneration(一) 源码解析

   目录

         一、CardGeneration

1、 构造函数

2、expand

3、compute_new_size

二、CMSBitMap

1、构造方法 / allocate

2、mark / par_mark / mark_range / par_mark_range / mark_large_range / par_mark_large_range

3、isMarked / par_isMarked / isUnmarked /isAllClear

4、par_clear / clear_range / par_clear_range / clear_large_range / par_clear_large_range /clear_all

5、getNextMarkedWordAddress / getNextUnmarkedWordAddress / getAndClearMarkedRegion

6、iterate / dirty_range_iterate_clear 

三、CMSMarkStack

1、构造方法和allocate

2、pop / push / par_pop / par_push

3、expand

四、ChunkArray


本篇博客讲解表示CMS老年代的ConcurrentMarkSweepGeneration的相关基础类的实现。

一、CardGeneration

    CardGeneration表示一个使用卡表来标记对象修改,使用BlockOffsetArray来记录内存块的起始位置的generation,继承自Generation,定义也在generation.hpp中,新增了如下属性:

  • GenRemSet* _rs; //与其他Generation实例共享的卡表实现实例
  • BlockOffsetSharedArray* _bts; //当前Generation独享的BlockOffsetArray实现
  • size_t _shrink_factor; //老年代内存缩容的百分比,第一次是0,第二次是10,第三次是40,第四次是100,中间有一次扩容了则被重置为0,重新开始累加,避免频繁的缩容与扩容。
  • size_t _min_heap_delta_bytes; //老年代内存扩展或者缩容时的最低内存值
  • size_t _capacity_at_prologue; //GC开始时的内存容量
  • size_t _used_at_prologue; //GC开始时的内存使用量

重点关注以下方法的实现。

1、 构造函数

CardGeneration::CardGeneration(ReservedSpace rs, size_t initial_byte_size,
                               int level,
                               GenRemSet* remset) :
  Generation(rs, initial_byte_size, level), _rs(remset),
  _shrink_factor(0), _min_heap_delta_bytes(), _capacity_at_prologue(),
  _used_at_prologue()
{
  HeapWord* start = (HeapWord*)rs.base();
  size_t reserved_byte_size = rs.size();
  //start地址和reserved_byte_size必须是4的整数倍
  assert((uintptr_t(start) & 3) == 0, "bad alignment");
  assert((reserved_byte_size & 3) == 0, "bad alignment");
  MemRegion reserved_mr(start, heap_word_size(reserved_byte_size));
  //初始化bts
  _bts = new BlockOffsetSharedArray(reserved_mr,
                                    heap_word_size(initial_byte_size));
  MemRegion committed_mr(start, heap_word_size(initial_byte_size));
  //重置卡表对应的内存区域
  _rs->resize_covered_region(committed_mr);
  if (_bts == NULL)
    vm_exit_during_initialization("Could not allocate a BlockOffsetArray");

  //校验start地址和end地址都对应某个卡表项的起始地址
  guarantee(_rs->is_aligned(reserved_mr.start()), "generation must be card aligned");
  if (reserved_mr.end() != Universe::heap()->reserved_region().end()) {
    guarantee(_rs->is_aligned(reserved_mr.end()), "generation must be card aligned");
  }
  //MinHeapDeltaBytes的取值是128k,表示扩展时的最低内存
  _min_heap_delta_bytes = MinHeapDeltaBytes;
  _capacity_at_prologue = initial_byte_size;
  _used_at_prologue = 0;
}

2、expand

      expand用于将内存扩展,第一个参数表示期望扩展的内存空间,第二个参数表示期望扩展的最低内存空间,如果扩展了一部分内存空间,即使小于最低内存空间,则返回true,底层会调用grow_by完成扩展,如果扩展失败则尝试grow_to_reserved。其实现如下:

//第一个参数bytes表示期望扩展的内存大小,第二个表示期望扩展的最低内存大小
bool CardGeneration::expand(size_t bytes, size_t expand_bytes) {
  assert_locked_or_safepoint(Heap_lock);
  if (bytes == 0) {
    return true;  // That's what grow_by(0) would return
  }
  //做内存对齐
  size_t aligned_bytes  = ReservedSpace::page_align_size_up(bytes);
  if (aligned_bytes == 0){
    aligned_bytes = ReservedSpace::page_align_size_down(bytes);
  }
  size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
  bool success = false;
  if (aligned_expand_bytes > aligned_bytes) {
    //扩展内存空间,正常来说aligned_bytes大于aligned_expand_bytes
    success = grow_by(aligned_expand_bytes);
  }
  if (!success) {
    success = grow_by(aligned_bytes);
  }
  if (!success) {
    //依然扩展失败,则尝试扩展至最大内存
    success = grow_to_reserved();
  }
  if (PrintGC && Verbose) {
    if (success && GC_locker::is_active_and_needs_gc()) {
      gclog_or_tty->print_cr("Garbage collection disabled, expanded heap instead");
    }
  }

  return success;
}

调用链如下:

3、compute_new_size

      该方法是在GC结束后根据参数MinHeapFreeRatio和MaxHeapFreeRatio以及当前内存的使用量来重新计算期望的容量,并做适当的扩容或者缩容处理,其实现如下:

void CardGeneration::compute_new_size() {
  assert(_shrink_factor <= 100, "invalid shrink factor");
  size_t current_shrink_factor = _shrink_factor;
  //将_shrink_factor置为0,后面缩容时会重新赋值
  _shrink_factor = 0;

  //MinHeapFreeRatio表示老年代空闲内存占总内存的最低百分比,默认值是80
  //计算最低的空闲百分比和最大的已使用百分比
  const double minimum_free_percentage = MinHeapFreeRatio / 100.0;
  const double maximum_used_percentage = 1.0 - minimum_free_percentage;

  //获取GC后的容量和已使用量
  const size_t used_after_gc = used();
  const size_t capacity_after_gc = capacity();

  //计算期望的最低容量,必须大于初始值
  const double min_tmp = used_after_gc / maximum_used_percentage;
  size_t minimum_desired_capacity = (size_t)MIN2(min_tmp, double(max_uintx));
  minimum_desired_capacity = MAX2(minimum_desired_capacity,
                                  spec()->init_size());
  assert(used_after_gc <= minimum_desired_capacity, "sanity check");

  if (PrintGC && Verbose) {
    const size_t free_after_gc = free();
    const double free_percentage = ((double)free_after_gc) / capacity_after_gc;
    gclog_or_tty->print_cr("TenuredGeneration::compute_new_size: ");
    gclog_or_tty->print_cr("  "
                  "  minimum_free_percentage: %6.2f"
                  "  maximum_used_percentage: %6.2f",
                  minimum_free_percentage,
                  maximum_used_percentage);
    gclog_or_tty->print_cr("  "
                  "   free_after_gc   : %6.1fK"
                  "   used_after_gc   : %6.1fK"
                  "   capacity_after_gc   : %6.1fK",
                  free_after_gc / (double) K,
                  used_after_gc / (double) K,
                  capacity_after_gc / (double) K);
    gclog_or_tty->print_cr("  "
                  "   free_percentage: %6.2f",
                  free_percentage);
  }

  if (capacity_after_gc < minimum_desired_capacity) {
    //当前容量小于期望的容量,需要扩容
    //计算期望扩容的量
    size_t expand_bytes = minimum_desired_capacity - capacity_after_gc;
    if (expand_bytes >= _min_heap_delta_bytes) {
      //必须大于最低扩容量才执行扩容
      expand(expand_bytes, 0); // safe if expansion fails
    }
    if (PrintGC && Verbose) {
      gclog_or_tty->print_cr("    expanding:"
                    "  minimum_desired_capacity: %6.1fK"
                    "  expand_bytes: %6.1fK"
                    "  _min_heap_delta_bytes: %6.1fK",
                    minimum_desired_capacity / (double) K,
                    expand_bytes / (double) K,
                    _min_heap_delta_bytes / (double) K);
    }
    return;
  }

  //当前容量大于期望的容量,需要缩容
  size_t shrink_bytes = 0;
  //计算缩容的容量
  size_t max_shrink_bytes = capacity_after_gc - minimum_desired_capacity;

  //MaxHeapFreeRatio表示空闲堆内存的最大百分比,默认是70%,用来避免缩容,通常用于老年代,但是G1和ParallelGC下应用于整个堆
  if (MaxHeapFreeRatio < 100) {
    //根据MaxHeapFreeRatio和used_after_gc计算期望的最大内存容量
    const double maximum_free_percentage = MaxHeapFreeRatio / 100.0;
    const double minimum_used_percentage = 1.0 - maximum_free_percentage;
    const double max_tmp = used_aft
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值