Hotspot 垃圾回收之EdenSpace 源碼解析

   目錄

一、GenSpaceMangler

1、定義

2、check_mangled_unused_area / check_mangled_unused_area_complete

 3、mangle_unused_area / mangle_unused_area_complete / mangle_region

二、ContiguousSpace

1、定義

2、構造方法 /initialize / clear

3、allocate / par_allocate /allocate_aligned /allocate_temporary_filler

4、block_start_const / block_size / block_is_obj / reset_after_compaction

5、oop_iterate / object_iterate/ safe_object_iterate / object_iterate_careful

6、par_oop_iterate / oop_since_save_marks_iterate

三、EdenSpace

四、ConcEdenSpace


本篇博客繼續上一篇《Hotspot 垃圾回收之Space(一) 源碼解析》講解Space的其他子類,重點關注CMS相關的子類。

一、GenSpaceMangler

1、定義

       GenSpaceMangler的定義在hotspot\src\share\vm\gc_implementation\shared\spaceDecorator.hpp中,是GenCollectedHeap用來給Space執行mangle動作的,所謂mangle實際就是把未使用的內存區域填充爲一個特定的值,通過這種方式強制操作系統提前分配好對應內存區域的內存頁,提升Space本身內存分配和對象初始化的效率,避免Space實際分配內存時或者已分配給對象的內存在實際賦值時才由操作系統分配內存頁。該類繼承自SpaceMangler,SpaceMangler的定義也在spaceDecorator.hpp中,其類繼承關係如下:

其中的MutableSpaceMangler是適用於PS算法的ParallelScavengeHeap的Space。 GenSpaceMangler在SpaceMangler的基礎上只增加了一個屬性,沒有新增方法,只提供了父類的虛方法的實現,其定義如下:

父類SpaceMangler只有一個屬性,如下:

_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下開啓,否則該方法是空實現。這兩方法的調用鏈如下:

兩者的實現如下:

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的,這三個方法的調用鏈如下:

 從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中上述方法都是默認的空實現,如下:

ContiguousSpace改寫了父類的prepare_for_compaction方法的實現,如下:

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();
}

 這三個方法的調用鏈如下:

 

 上述方法中並沒有直接初始化Space的top屬性的代碼,那麼該屬性是怎麼初始化的了?答案是initialize方法,查看initialize的具體調用可知,傳入initialize方法的第二個參數clear_space基本都是true,該參數爲true時會在執行父類Space::initialize方法時反過來調用子類的ContiguousSpace::clear方法,該方法執行時將bottom屬性賦值給top屬性。以CompactibleFreeListSpace中的調用爲例,如下圖:

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

 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的可用內存,從而觸發垃圾回收。這幾個方法的調用鏈如下:

  

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();
}

上述方法的調用鏈如下:

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())

上述幾個方法的調用鏈如下:

上述方法中用到的WaterMark是一個非常簡單的數據結構,來保存起始地址和關聯的Space的,其定義在memory/watermark.hpp中,如下:

6、par_oop_iterate / oop_since_save_marks_iterate

     這兩方法都是通過宏定義的,實際是有多個重載版本,如下圖:

這些方法的實現也是通過宏實現的,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

       EdenSpace繼承自ContiguousSpace,其定義也在space.hpp中,用來表示Eden區。EdenSpace增加了兩個屬性,如下:

其中_gen就是關聯的年輕代DefNewGeneration實例,_soft_end是分配內存的一個軟限制, 當達到了這個限制後,慢速分配的代碼可以執行其他的邏輯,然後調整_soft_end到一個新的限制或者end(),參考set_soft_end方法的調用鏈,如下:

除第一個方法外,後面三個方法都是將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構造方法的調用鏈,如下:

具體使用如下:

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

開啓CMS下,默認使用的CollectorPolicy的子類是ASConcurrentMarkSweepPolicy,ASConcurrentMarkSweepPolicy的父類ConcurrentMarkSweepPolicy改寫了默認的has_soft_ended_eden的實現,如下:

CMSIncrementalMode表示是否開啓增量收集模式,如果開啓則has_soft_ended_eden返回true,該屬性默認是false,增量模式是指增量的執行垃圾回收,將這個垃圾回收的週期延長,主要適用於單CPU下,避免垃圾回收線程佔用CPU太久導致業務線程停頓太久。爲什麼開啓增量模式下必須使用ConcEdenSpace且待後面DefNewGeneration的詳細探討。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章