EdenSpace

作者: 程序员札记 | 来源:发表于2022-11-08 12:07 被阅读0次

    本篇博客继续上一篇CompactibleSpace讲解Space的其他子类,重点关注CMS相关的子类。

    GenSpaceMangler

    1、定义
    GenSpaceMangler的定义在hotspot\src\share\vm\gc_implementation\shared\spaceDecorator.hpp中,是GenCollectedHeap用来给Space执行mangle动作的,所谓mangle实际就是把未使用的内存区域填充为一个特定的值,通过这种方式强制操作系统提前分配好对应内存区域的内存页,提升Space本身内存分配和对象初始化的效率,避免Space实际分配内存时或者已分配给对象的内存在实际赋值时才由操作系统分配内存页。该类继承自SpaceMangler,SpaceMangler的定义也在spaceDecorator.hpp中,其类继承关系如下:

    image.png

    其中的MutableSpaceMangler是适用于PS算法的ParallelScavengeHeap的Space。 GenSpaceMangler在SpaceMangler的基础上只增加了一个属性,没有新增方法,只提供了父类的虚方法的实现,其定义如下:


    image.png

    父类SpaceMangler只有一个属性,如下:

    image.png

    _top_for_allocations记录了Space中已分配出去的内存区域,在此之前的内存区域已经被分配了,之后的区域未被分配,因为之前Space初始化的时候已经执行过mangle了,所以不需要再次mangle了。 重点关注以下父类方法的实现。

    2、check_mangled_unused_area / check_mangled_unused_area_complete
    这两个方法都是用于检查已经执行过mangle的Space的内存区域是否被正确mangle了,其中check_mangled_unused_area只是校验了起止地址是否mangle了,check_mangled_unused_area_complete是对起止地址之间的整块内存区域都执行了mangle,因为需要遍历一遍整块内存区域,所以比较费时,只在调试mangle下开启,否则该方法是空实现。这两方法的调用链如下:

    image.png

    两者的实现如下:

    void  SpaceMangler::check_mangled_unused_area(HeapWord* limit) {
      //CheckZapUnusedHeapArea表示是否检查未使用的内存区域是否执行了zap,默认为false
      if (CheckZapUnusedHeapArea) {
        // 当Space执行reshaped后,end地址就会大于limit,不再执行检查
        if (end() > limit) return;
        
        //检查如下参数是否整数
        assert(top() == end() ||
               (is_mangled(top())), "Top not mangled");
        assert((top_for_allocations() < top()) ||
               (top_for_allocations() >= end()) ||
               (is_mangled(top_for_allocations())),
               "Older unused not mangled");
        assert(top() == end() ||
               (is_mangled(end() - 1)), "End not properly mangled");
        // Only does checking when DEBUG_MANGLING is defined.
        check_mangled_unused_area_complete();
      }
    }
     
    void  SpaceMangler::check_mangled_unused_area_complete() {
      if (CheckZapUnusedHeapArea) {
        assert(ZapUnusedHeapArea, "Not mangling unused area");
    #ifdef DEBUG_MANGLING
        HeapWord* q = top();
        HeapWord* limit = end();
     
        bool passed = true;
        //逐一遍历q和limit之间的内存区域
        while (q < limit) {
          if (!is_mangled(q)) {
            passed = false;
            break;
          }
          q++;
        }
        assert(passed, "Mangling is not complete");
    #endif
      }
    }
     
    //检查某个地址的数据是否是指定值,如果是则认为已经mangle了
    bool SpaceMangler::is_mangled(HeapWord* q) {
      // This test loses precision but is good enough
      return badHeapWord == (max_juint & (uintptr_t) q->value());
    }
     
    #define       badHeapWord       (::badHeapWordVal)
     
    const juint    badHeapWordVal   = 0xBAADBABE;               // value used to zap heap after GC
    

    3、mangle_unused_area / mangle_unused_area_complete / mangle_region
    mangle_unused_area和mangle_unused_area_complete都是将关联的Space的未使用的内存区域执行mangle,不同的是范围不同,两者最终都是调用mangle_region将指定的内存区域mangle的,这三个方法的调用链如下:

    image.png image.png
    image.png

    从mangle_region的调用链可知,当Space初始化或者扩展或者GC完成的时候都需要执行mangle,参考SpaceMangler的注释,当从Space中完成一次内存分配,也需要对分配的内存执行mangle。这三个方法的实现如下:

    void SpaceMangler::mangle_unused_area() {
      //ZapUnusedHeapArea表示是否填充未使用的内存区域,这里校验该配置必须为true
      assert(ZapUnusedHeapArea, "Mangling should not be in use");
      // Mangle between top and the high water mark.  Safeguard
      // against the space changing since top_for_allocations was
      // set.
      HeapWord* mangled_end = MIN2(top_for_allocations(), end());
      if (top() < mangled_end) {
        MemRegion mangle_mr(top(), mangled_end);
        //执行填充
        SpaceMangler::mangle_region(mangle_mr);
        //轻量级的检查
        check_mangled_unused_area(end());
      }
      // Complete check of unused area which is functional when
      // DEBUG_MANGLING is defined.
      check_mangled_unused_area_complete();
    }
     
    void SpaceMangler::mangle_unused_area_complete() {
      assert(ZapUnusedHeapArea, "Mangling should not be in use");
      MemRegion mangle_mr(top(), end());
      SpaceMangler::mangle_region(mangle_mr);
    }
     
    void SpaceMangler::mangle_region(MemRegion mr) {
      assert(ZapUnusedHeapArea, "Mangling should not be in use");
    #ifdef ASSERT
      if(TraceZapUnusedHeapArea) {
        gclog_or_tty->print("Mangling [0x%x to 0x%x)", mr.start(), mr.end());
      }
      //将指定的内存区域赋值为badHeapWord
      Copy::fill_to_words(mr.start(), mr.word_size(), badHeapWord);
      if(TraceZapUnusedHeapArea) {
        gclog_or_tty->print_cr(" done");
      }
    #endif
    }
    

    ContiguousSpace

    1、定义
    ContiguousSpace继承自CompactibleSpace,其定义在space.hpp中,表示一个空闲内存空间是地址连续的Space,从而支持快速的内存分配和压缩。ContiguousSpace只添加了三个属性,如下:

    • HeapWord* _top; //bottom到top之间的内存都是已经被分配出去的内存
    • HeapWord* _concurrent_iteration_safe_limit; //从bottom到_concurrent_iteration_safe_limit之间的对象都被认为是已经初始化完成的对象,对于object_iterate_careful方法可以安全遍历的,该属性在初始化时通常设置为bottom,在compact结束后设置为compact_top。
    • GenSpaceMangler* _mangler; //负责对Space执行mangle的辅助类

    _mangler属性主要用于实现Space中定义的mangle_unused_area等方法,不过需要注意ContiguousSpace对上述方法的实现是在非生产版本中才有的,如下:


    -

    Space中上述方法都是默认的空实现,如下:


    image.png

    ContiguousSpace改写了父类的prepare_for_compaction方法的实现,如下:


    image.png

    end换成了top,因为top之前的区域才分配了对象,之后的区域都是未使用的空间;block_is_obj换成了block_is_always_obj,实际返回true,因为top之前内存块都是对象,这样更改可以更快的查找需要被移动的被标记的对象。 除此之外,重点关注以下方法的实现。

    2、构造方法 /initialize / clear
    ContiguousSpace改写了父类方法的实现,如下:

    //注意这里的top和_concurrent_iteration_safe_limit属性都是初始化为NULL
    ContiguousSpace::ContiguousSpace(): CompactibleSpace(), _top(NULL),
        _concurrent_iteration_safe_limit(NULL) {
      _mangler = new GenSpaceMangler(this);
    }
     
    ContiguousSpace::~ContiguousSpace() {
      delete _mangler;
    }
     
    void ContiguousSpace::initialize(MemRegion mr,
                                     bool clear_space,
                                     bool mangle_space)
    {
      CompactibleSpace::initialize(mr, clear_space, mangle_space);
      set_concurrent_iteration_safe_limit(top());
    }
     
    void CompactibleSpace::initialize(MemRegion mr,
                                      bool clear_space,
                                      bool mangle_space) {
      Space::initialize(mr, clear_space, mangle_space);
      set_compaction_top(bottom());
      _next_compaction_space = NULL;
    }
     
    HeapWord* top() const            { return _top;    }
     
    void ContiguousSpace::clear(bool mangle_space) {
      set_top(bottom());
      set_saved_mark();
      CompactibleSpace::clear(mangle_space);
    }
     
    void set_top(HeapWord* value)    { _top = value; }
     
    void set_saved_mark()            { _saved_mark_word = top();    }
     
    void CompactibleSpace::clear(bool mangle_space) {
      Space::clear(mangle_space);
      _compaction_top = bottom();
    }
     
    void Space::clear(bool mangle_space) {
      if (ZapUnusedHeapArea && mangle_space) {
        mangle_unused_area();
      }
    }
     
    void ContiguousSpace::mangle_unused_area() {
      mangler()->mangle_unused_area();
    }
    

    这三个方法的调用链如下:

    image.png image.png image.png

    上述方法中并没有直接初始化Space的top属性的代码,那么该属性是怎么初始化的了?答案是initialize方法,查看initialize的具体调用可知,传入initialize方法的第二个参数clear_space基本都是true,该参数为true时会在执行父类Space::initialize方法时反过来调用子类的ContiguousSpace::clear方法,该方法执行时将bottom属性赋值给top属性。以CompactibleFreeListSpace中的调用为例,如下图:


    image.png

    SpaceDecorator::Clear和SpaceDecorator::Mangle的定义如下:


    image.png

    SpaceDecorator类的定义和GenSpaceMangler在同一个文件中。

    3、allocate / par_allocate /allocate_aligned /allocate_temporary_filler
    前面三个方法都是用来执行内存分配,不同的是allocate方法要求调用方已经获取了锁,par_allocate不要求调用方获取锁,该方法内部会原子的修改top属性,修改失败再重试,allocate_aligned方法要求调用方获取了锁Heap_lock或者是一个VMThread且处于安全点上,在执行分配前会先将top地址按照Survivor内存分配的粒度对齐,如果没有对齐则填充至对齐。allocate_temporary_filler是将当前的Space的剩余未分配空间分配成一个int数组或者Object对象,通过factor控制使用的剩余未分配空间的量,如果factor为0,表示整个剩余未分配空间会被全部利用,该方法用于主要耗尽Space的可用内存,从而触发垃圾回收。这几个方法的调用链如下:

    image.png image.png image.png

    allocate_temporary_filler没有调用方,他们的实现如下:

    //要求调用方已经获取了锁
    HeapWord* ContiguousSpace::allocate(size_t size) {
      return allocate_impl(size, end());
    }
     
    //不要求获取锁,方法内部会重试
    HeapWord* ContiguousSpace::par_allocate(size_t size) {
      return par_allocate_impl(size, end());
    }
     
    HeapWord* ContiguousSpace::allocate_aligned(size_t size) {
      //校验当前线程已经获取了Heap_lock或者是一个VMThread且处于安全点上
      assert(Heap_lock->owned_by_self() || (SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread()), "not locked");
      HeapWord* end_value = end();
      //SurvivorAlignmentInBytes表示Survivor内存分配的粒度,align_allocation_or_fail方法是将top地址按照SurvivorAlignmentInBytes对齐
      //如果没有对齐则填充,如果对齐后超过end_value则返回Null
      HeapWord* obj = CollectedHeap::align_allocation_or_fail(top(), end_value, SurvivorAlignmentInBytes);
      if (obj == NULL) {
        return NULL;
      }
      
      //判断top和end之间的内存空间是否充足
      if (pointer_delta(end_value, obj) >= size) {
        /如果充足则向上移动top
        HeapWord* new_top = obj + size;
        set_top(new_top);
        assert(is_ptr_aligned(obj, SurvivorAlignmentInBytes) && is_aligned(new_top),
          "checking alignment");
        return obj;
      } else {
        //空间不够,同样修改top,返回NULL
        set_top(obj);
        return NULL;
      }
    }
     
    void ContiguousSpace::allocate_temporary_filler(int factor) {
      // allocate temporary type array decreasing free size with factor 'factor'
      assert(factor >= 0, "just checking");
      //计算剩余空间
      size_t size = pointer_delta(end(), top());
     
      // if space is full, return
      if (size == 0) return;
      
      //计算本次分配的空间
      if (factor > 0) {
        size -= size/factor;
      }
      //内存对齐
      size = align_object_size(size);
      //获取int数组的对象头大小
      const size_t array_header_size = typeArrayOopDesc::header_size(T_INT);
      if (size >= (size_t)align_object_size(array_header_size)) {
        //满足int数组的最低值,计算其数组长度
        size_t length = (size - array_header_size) * (HeapWordSize / sizeof(jint));
        //分配指定大小的内存
        typeArrayOop t = (typeArrayOop) allocate(size);
        assert(t != NULL, "allocation should succeed");
        //设置int数组的属性
        t->set_mark(markOopDesc::prototype());
        t->set_klass(Universe::intArrayKlassObj());
        t->set_length((int)length);
      } else {
        //不能满足int数组的大小,只能是java.lang.Object
        assert(size == CollectedHeap::min_fill_size(),
               "size for smallest fake object doesn't match");
        instanceOop obj = (instanceOop) allocate(size);
        //设置obj的基础属性
        obj->set_mark(markOopDesc::prototype());
        obj->set_klass_gap(0);
        obj->set_klass(SystemDictionary::Object_klass());
      }
    }
     
    inline HeapWord* ContiguousSpace::allocate_impl(size_t size,
                                                    HeapWord* const end_value) {
      assert(Heap_lock->owned_by_self() ||
             (SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread()),
             "not locked");
      HeapWord* obj = top();
      //判断top和end之间的内存空间是否充足
      if (pointer_delta(end_value, obj) >= size) {
        //如果充足则向上移动top
        HeapWord* new_top = obj + size;
        set_top(new_top);
        assert(is_aligned(obj) && is_aligned(new_top), "checking alignment");
        return obj;
      } else {
        //不充足返回NULL
        return NULL;
      }
    }
     
    inline HeapWord* ContiguousSpace::par_allocate_impl(size_t size,
                                                        HeapWord* const end_value) {
      do {
        HeapWord* obj = top();
        //判断top和end之间的内存空间是否充足
        if (pointer_delta(end_value, obj) >= size) {
          HeapWord* new_top = obj + size;
          //如果充足则修改top
          HeapWord* result = (HeapWord*)Atomic::cmpxchg_ptr(new_top, top_addr(), obj);
          if (result == obj) {
            //说明修改成功,如果返回其他的值,说明top被其他线程修改了,通过while循环再次重试
            assert(is_aligned(obj) && is_aligned(new_top), "checking alignment");
            return obj;
          }
        } else {
          //空间不足返回NULL
          return NULL;
        }
      } while (true);
    }
    

    4、block_start_const / block_size / block_is_obj / reset_after_compaction
    上述几个方法是Space压缩时用到的方法,父类没有给出默认实现,其中block_start_const方法返回包含指定地址p的内存块的起始地址;block_size返回指定地址addr处的内存块的大小;block_is_obj 返回指定地址addr处的内存块是否是一个对象;reset_after_compaction方法用于在当前Space执行compact后重置Space的,主要操作就是将compaction_top置为top,因为compaction_top之前的内存区域已经分配给在compact过程中被移动的对象了。其实现如下:

    HeapWord* ContiguousSpace::block_start_const(const void* p) const {
      //校验当前Space包含地址p
      assert(MemRegion(bottom(), end()).contains(p),
             err_msg("p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")",
                      p, bottom(), end()));
      if (p >= top()) {
        //如果p大于top,说明p所处的内存未分配则返回top
        return top();
      } else {
        HeapWord* last = bottom();
        HeapWord* cur = last;
        //从bottom开始遍历所有的对象
        while (cur <= p) {
          last = cur;
          cur += oop(cur)->size();
        }
        //找到包含p的对象,该对象起始地址是last,
        assert(oop(last)->is_oop(),
               err_msg(PTR_FORMAT " should be an object start", last));
        return last;
      }
    }
     
    size_t ContiguousSpace::block_size(const HeapWord* p) const {
      //校验p在Space中
      assert(MemRegion(bottom(), end()).contains(p),
             err_msg("p (" PTR_FORMAT ") not in space [" PTR_FORMAT ", " PTR_FORMAT ")",
                      p, bottom(), end()));
      HeapWord* current_top = top();
      //校验p要么小于top,是一个对象,要么等于top
      assert(p <= current_top,
             err_msg("p > current top - p: " PTR_FORMAT ", current top: " PTR_FORMAT,
                      p, current_top));
      assert(p == current_top || oop(p)->is_oop(),
             err_msg("p (" PTR_FORMAT ") is not a block start - "
                     "current_top: " PTR_FORMAT ", is_oop: %s",
                     p, current_top, BOOL_TO_STR(oop(p)->is_oop())));
      if (p < current_top) {
        //小于top,返回对象大小
        return oop(p)->size();
      } else {
        //等于top,返回p到end的剩余空间大小
        assert(p == current_top, "just checking");
        return pointer_delta(end(), (HeapWord*) p);
      }
    }
     
     //如果p小于top,说明p位于已分配内存区域,认为其是一个对象
     bool block_is_obj(const HeapWord* p) const { return p < top(); }
     
     virtual void reset_after_compaction() {
        assert(compaction_top() >= bottom() && compaction_top() <= end(), "should point inside space");
        //将compaction_top置为top,因为执行compact后,compaction_top之前的区域已经分配给哪些被标记的被移动的对象了
        set_top(compaction_top());
        // set new iteration safe limit
        set_concurrent_iteration_safe_limit(compaction_top());
      }
     
    inline int oopDesc::size()  {
      //根据oop所属的Klass获取对象大小
      return size_given_klass(klass());
    }
     
    // used only for asserts
    inline bool oopDesc::is_oop(bool ignore_mark_word) const {
      oop obj = (oop) this;
      //校验地址是内存对齐的
      if (!check_obj_alignment(obj)) return false;
      //校验oop在Java堆内存范围内
      if (!Universe::heap()->is_in_reserved(obj)) return false;
      //校验oop的Klass在Java堆内存范围内
      if (Universe::heap()->is_in_reserved(obj->klass_or_null())) return false;
      
      if (ignore_mark_word) {
        return true;
      }
      //校验请求头,通常都不为NULL
      if (mark() != NULL) {
        return true;
      }
      //如果不在安全点上,该对象的对象头可能为空
      return !SafepointSynchronize::is_at_safepoint();
    }
    

    上述方法的调用链如下:

    image.png image.png
    image.png image.png

    5、oop_iterate / object_iterate/ safe_object_iterate / object_iterate_careful
    这四个方法都是用于遍历Space中包含的oop,其中oop_iterate是遍历每一个包含的oop对应Java对象的所有引用类型的属性;object_iterate的实现就是object_iterate_from,object_iterate从bottom处开始遍历,object_iterate_from可以指定遍历的起始地址,这两个都是遍历Space中包含的oop本身;safe_object_iterate 方法在Space中的定义是要求遍历那些内部引用所指向的对象同样是在Space里的,但是对于ContiguousSpace是一样的;object_iterate_careful是遍历bottom到_concurrent_iteration_safe_limit之间的oop,这些oop通常都是已经完成初始化的,如果遍历过程中遇到未初始化的对象则终止遍历。其实现如下:

    void ContiguousSpace::oop_iterate(ExtendedOopClosure* blk) {
      //如果Space未分配对象则返回
      if (is_empty()) return;
      HeapWord* obj_addr = bottom();
      HeapWord* t = top();
      //遍历Space中所有对象
      while (obj_addr < t) {
        //遍历对象obj_addr所有的引用属性oop
        obj_addr += oop(obj_addr)->oop_iterate(blk);
      }
    }
     
    void ContiguousSpace::object_iterate(ObjectClosure* blk) {
      if (is_empty()) return;
      WaterMark bm = bottom_mark();
      object_iterate_from(bm, blk);
    }
     
    void ContiguousSpace::object_iterate_from(WaterMark mark, ObjectClosure* blk) {
      assert(mark.space() == this, "Mark does not match space");
      //获取遍历的起始地址
      HeapWord* p = mark.point();
      while (p < top()) {
        //只是遍历Space中包含的oop本身
        blk->do_object(oop(p));
        p += oop(p)->size();
      }
    }
     
    // For a continguous space object_iterate() and safe_object_iterate()
    // are the same.
    void ContiguousSpace::safe_object_iterate(ObjectClosure* blk) {
      object_iterate(blk);
    }
     
    HeapWord*
    ContiguousSpace::object_iterate_careful(ObjectClosureCareful* blk) {
      HeapWord * limit = concurrent_iteration_safe_limit();
      assert(limit <= top(), "sanity check");
      for (HeapWord* p = bottom(); p < limit;) {
        size_t size = blk->do_object_careful(oop(p));
        if (size == 0) {
          return p;  // 如果blk遍历失败,因为p是一个未初始化的对象或者blk异常终止了
        } else {
          p += size;
        }
      }
      return NULL; //如果所有已初始化的对象都遍历完成则返回NULL
    }
     
    bool is_empty() const              { return used() == 0; }
     
    size_t used() const            { return byte_size(bottom(), top()); }
     
    WaterMark bottom_mark()     { return WaterMark(this, bottom()); }
     
    HeapWord* concurrent_iteration_safe_limit() {
        assert(_concurrent_iteration_safe_limit <= top(),
               "_concurrent_iteration_safe_limit update missed");
        return _concurrent_iteration_safe_limit;
      }
     
    inline int oopDesc::oop_iterate(ExtendedOopClosure* blk) { 
      //record_call在非生产版本中为空实现                    
      SpecializationStats::record_call();
      return klass()->oop_oop_iterate_v(this, blk);               
    }  
     
    #define InstanceKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)        \
                                                                                 \
    int InstanceKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) { \
      SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::ik);\
      /* header */                                                          \
      if_do_metadata_checked(closure, nv_suffix) {                          \
        //检查klass
        closure->do_klass##nv_suffix(obj->klass());                         \
      }                                                                     \
      //遍历obj的所有引用类型属性,执行(closure)->do_oop##nv_suffix(p)方法
      InstanceKlass_OOP_MAP_ITERATE(                                        \
        obj,                                                                \
        SpecializationStats::                                               \
          record_do_oop_call##nv_suffix(SpecializationStats::ik);           \
        (closure)->do_oop##nv_suffix(p),                                    \
        assert_is_in_closed_subset)                                         \
        //返回该对象的大小
      return size_helper();                                                 \
    }
     
    #define if_do_metadata_checked(closure, nv_suffix)       \
      /* Make sure the non-virtual and the virtual versions match. */     \
      assert(closure->do_metadata##nv_suffix() == closure->do_metadata(), \
          "Inconsistency in do_metadata");                                \
      if (closure->do_metadata##nv_suffix())
    

    上述几个方法的调用链如下:

    image.png
    image.png image.png image.png

    上述方法中用到的WaterMark是一个非常简单的数据结构,来保存起始地址和关联的Space的,其定义在memory/watermark.hpp中,如下:

    image.png

    6、par_oop_iterate / oop_since_save_marks_iterate
    这两方法都是通过宏定义的,实际是有多个重载版本,如下图:


    image.png
    image.png

    这些方法的实现也是通过宏实现的,par_oop_iterate 用于遍历指定的内存区域MemRegion中的oop,oop_since_save_marks_iterate是遍历_saved_mark_word到top之间的oop,两者都是遍历oop对应对象所引用的所有引用类型属性,实现如下:

    //ALL_PAR_OOP_ITERATE_CLOSURES宏定义了各种OopClosureType
    //ContigSpace_PAR_OOP_ITERATE_DEFN定义了具体的方法实现
    ALL_PAR_OOP_ITERATE_CLOSURES(ContigSpace_PAR_OOP_ITERATE_DEFN)
    
    #define ALL_PAR_OOP_ITERATE_CLOSURES(f)                \
     f(ExtendedOopClosure,_v) 
     //SPECIALIZED_PAR_OOP_ITERATE_CLOSURES同样是定义其他的OopClosureType                            \
     SPECIALIZED_PAR_OOP_ITERATE_CLOSURES(f)
    #endif // INCLUDE_ALL_GCS
    
    #define ContigSpace_PAR_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)         \
                                                                               \
     void ContiguousSpace::par_oop_iterate(MemRegion mr, OopClosureType* blk) {\
       HeapWord* obj_addr = mr.start();                                        \
       HeapWord* t = mr.end();                                                 \
       //遍历指定内存区域的所有oop
       while (obj_addr < t) {                                                  \
         assert(oop(obj_addr)->is_oop(), "Should be an oop");                  \
         //遍历obj_addr对象中所有引用类型的属性对应的oop
         obj_addr += oop(obj_addr)->oop_iterate(blk);                          \
       }                                                                       \
     }
    
    
    //定义方式同上,ALL_SINCE_SAVE_MARKS_CLOSURES定义重载的版本
    //ContigSpace_OOP_SINCE_SAVE_MARKS_DEFN定义具体的实现
    ALL_SINCE_SAVE_MARKS_CLOSURES(ContigSpace_OOP_SINCE_SAVE_MARKS_DEFN)
    
    #define ALL_SINCE_SAVE_MARKS_CLOSURES(f)                \
     f(OopsInGenClosure,_v)                                \
     SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES(f)
    
    #define ContigSpace_OOP_SINCE_SAVE_MARKS_DEFN(OopClosureType, nv_suffix)  \
                                                                             \
    void ContiguousSpace::                                                    \
    oop_since_save_marks_iterate##nv_suffix(OopClosureType* blk) {            \
     HeapWord* t;                                                            \
     HeapWord* p = saved_mark_word();                                        \
     assert(p != NULL, "expected saved mark");                               \
                                                                             \
     const intx interval = PrefetchScanIntervalInBytes;                      \
     do {                                                                    \
       t = top();                                                            \
       //不断遍历_saved_mark_word到top之间的对象
       while (p < t) {                                                       \
         //预先加载p处的内存数据
         Prefetch::write(p, interval);                                       \
         debug_only(HeapWord* prev = p);                                     \
         oop m = oop(p);                                                     \
         ///遍历m对象中所有引用类型的属性对应的oop
         p += m->oop_iterate(blk);                                           \
       }                                                                     \
     } while (t < top());                                                    \
                                                                             \
     set_saved_mark_word(p);                                                 \
    }
    
    virtual HeapWord* saved_mark_word() const  { return _saved_mark_word; }
    

    EdenSpace继承自ContiguousSpace,其定义也在space.hpp中,用来表示Eden区。EdenSpace增加了两个属性,如下:


    image.png

    其中_gen就是关联的年轻代DefNewGeneration实例,_soft_end是分配内存的一个软限制, 当达到了这个限制后,慢速分配的代码可以执行其他的逻辑,然后调整_soft_end到一个新的限制或者end(),参考set_soft_end方法的调用链,如下:

    image.png

    除第一个方法外,后面三个方法都是将end()赋值给_soft_end。为了实现_soft_end作为分配内存的软限制,EdenSpace改写了如下方法的实现:

    void set_end(HeapWord* value) {
        set_soft_end(value);
        ContiguousSpace::set_end(value);
    }
     
    void EdenSpace::clear(bool mangle_space) {
      ContiguousSpace::clear(mangle_space);
      set_soft_end(end());
    }
     
    //ContiguousSpace的实现传入的是end
    HeapWord* EdenSpace::allocate(size_t size) {
      return allocate_impl(size, soft_end());
    }
     
    // Lock-free.
    HeapWord* EdenSpace::par_allocate(size_t size) {
      return par_allocate_impl(size, soft_end());
    }
    

    ConcEdenSpace

    ConcEdenSpace继承自EdenSpace,其定义也在space.hpp中,ConcEdenSpace修改了EdenSpace中par_allocate的实现,从而允许在内存分配时并发的修改_soft_end属性,其实现如下:

    HeapWord* ConcEdenSpace::par_allocate(size_t size)
    {
      do {
        //在并发修改soft_end和指令重排序的情况下,如果先读取soft_end,读取完了soft_end和top被并发修改变大了,
        //再读取top,top就会小于原来的soft_end,导致分配失败;如果先读取top,再读取soft_end,则top一定会小于soft_end
        //添加OrderAccess::loadload保证top属性的读取在soft_end的前面
        HeapWord* obj = top();
        OrderAccess::loadload();
        //判断剩余空间是否充足
        if (pointer_delta(*soft_end_addr(), obj) >= size) {
          HeapWord* new_top = obj + size;
          //原子的修改top属性
          HeapWord* result = (HeapWord*)Atomic::cmpxchg_ptr(new_top, top_addr(), obj);
          if (result == obj) {
            //修改成功
            assert(is_aligned(obj) && is_aligned(new_top), "checking alignment");
            return obj;
          }
          //修改失败重试
        } else {
          //剩余空间不足
          return NULL;
        }
      } while (true);
    }
     
    HeapWord** soft_end_addr()         { return &_soft_end; }
    

    那么什么时候使用ConcEdenSpace,什么时候使用EdenSpace了,参考ConcEdenSpace构造方法的调用链,如下:

    image.png

    具体使用如下:


    image.png

    如果has_soft_ended_eden返回true则使用ConcEdenSpace,否则使用EdenSpace。has_soft_ended_eden在CollectorPolicy中默认是返回false,如下:


    image.png

    开启CMS下,默认使用的CollectorPolicy的子类是ASConcurrentMarkSweepPolicy,ASConcurrentMarkSweepPolicy的父类ConcurrentMarkSweepPolicy改写了默认的has_soft_ended_eden的实现,如下:


    image.png

    CMSIncrementalMode表示是否开启增量收集模式,如果开启则has_soft_ended_eden返回true,该属性默认是false,增量模式是指增量的执行垃圾回收,将这个垃圾回收的周期延长,主要适用于单CPU下,避免垃圾回收线程占用CPU太久导致业务线程停顿太久。为什么开启增量模式下必须使用ConcEdenSpace且待后面DefNewGeneration的详细探讨。

    相关文章

      网友评论

          本文标题:EdenSpace

          本文链接:https://www.haomeiwen.com/subject/ficntdtx.html