Hotspot 垃圾回收之oop_iterate(二) 源码解析

  目录

1、java.lang.Class

1.1、Class实例中oop_size、klass等属性是哪来的?

1.2、_offset_of_static_fields

1.3 为什么从_offset_of_static_fields处开始遍历?

2、InstanceRefKlass

3、ObjArrayKlass

4、oopDesc::adjust_pointers / follow_contents

4.1、InstanceKlass

 4.2、InstanceClassLoaderKlass

4.3、InstanceMirrorKlass

4.4、InstanceRefKlass

4.6、TypeArrayKlass

4.7、ObjArrayKlass


本篇博客继续上一篇《Hotspot 垃圾回收之oop_iterate(一) 源码解析》讲解其他Klass子类的oop_oop_iterate方法的实现细节和同样是GC支持的oopDesc::adjust_pointers / follow_contents方法的实现。

1、java.lang.Class

     理解InstanceMirrorKlass的引用遍历逻辑,我们需要逐步弄清楚以下几个问题:

1.1、Class实例中oop_size、klass等属性是哪来的?

   查看java.lang.Class的源码可知,该类并没有oop_size、klass等属性的声明,但是通过HSDB查看该类的Klass确实有该属性,测试用例如下:

package jvmTest;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;

class Base{
    public static int a=1;

    public static String s="abc";

    public static Integer a2=6;

    public static Integer a3=8;

    public static int a4=4;

    private int a5=12;

    private Integer a6=13;

    private int a7=13;
}

public class MainTest {

    public static void main(String[] args) {
        Class a=Base.class;
        System.out.println(Base.a);
        while (true){
            try {
                System.out.println(getProcessID());
                Thread.sleep(600*1000);
            } catch (Exception e) {

            }
        }
    }

    public static final int getProcessID() {
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        System.out.println(runtimeMXBean.getName());
        return Integer.valueOf(runtimeMXBean.getName().split("@")[0])
                .intValue();
    }
}

在Class Browser中搜索java.lang.Class,第一个便是该类对应的Klass,如下图:

点击该类可以发现该类其实是有很多属性的,如下:

上述private开头的属性在源码中都可以找到,就是比较分散隐蔽,从klass开始的剩余几个属性在源码中都没有,那这些属性是谁加进去的,什么时候加进去的了?答案是JVM,JVM在解析class文件中包含的属性时判断是java.lang.Class就会注入一部分字段放到属性的解析结果Array<u2>中,关键代码在负责字段解析的ClassFileParser::parse_fields方法中,如下图:

其中JavaClasses::get_injected就是返回需要注入的字段数组,其实现如下:

InjectedField* JavaClasses::get_injected(Symbol* class_name, int* field_count) {
  *field_count = 0;

  vmSymbols::SID sid = vmSymbols::find_sid(class_name);
  if (sid == vmSymbols::NO_SID) {
    // Only well known classes can inject fields
    return NULL;
  }

  int count = 0;
  int start = -1;

#define LOOKUP_INJECTED_FIELD(klass, name, signature, may_be_java) \
  if (sid == vmSymbols::VM_SYMBOL_ENUM_NAME(klass)) {              \
    //如果klass一致则增加count
    count++;                                                       \
    //如果start未初始化,则初始化,表示数组的起始位置
    if (start == -1) start = klass##_##name##_enum;                \
  }
  ALL_INJECTED_FIELDS(LOOKUP_INJECTED_FIELD);
#undef LOOKUP_INJECTED_FIELD

  if (start != -1) {
    //如果找到了,将field_count置为count
    *field_count = count;
    //返回_injected_fields数组中start处开始的元素,元素个数就是count
    return _injected_fields + start;
  }
  return NULL;
}

#define ALL_INJECTED_FIELDS(macro)          \
  CLASS_INJECTED_FIELDS(macro)              \
  CLASSLOADER_INJECTED_FIELDS(macro)        \
  MEMBERNAME_INJECTED_FIELDS(macro)

//java.lang.Class中新增的属性
#define CLASS_INJECTED_FIELDS(macro)                                       \
  macro(java_lang_Class, klass,                  intptr_signature,  false) \
  macro(java_lang_Class, array_klass,            intptr_signature,  false) \
  macro(java_lang_Class, oop_size,               int_signature,     false) \
  macro(java_lang_Class, static_oop_field_count, int_signature,     false) \
  macro(java_lang_Class, protection_domain,      object_signature,  false) \
  macro(java_lang_Class, init_lock,              object_signature,  false) \
  macro(java_lang_Class, signers,                object_signature,  false)

//_injected_fields是一个InjectedField数组
InjectedField JavaClasses::_injected_fields[] = {
  ALL_INJECTED_FIELDS(DECLARE_INJECTED_FIELD)
};

#define DECLARE_INJECTED_FIELD(klass, name, signature, may_be_java)           \
  { SystemDictionary::WK_KLASS_ENUM_NAME(klass), vmSymbols::VM_SYMBOL_ENUM_NAME(name##_name), vmSymbols::VM_SYMBOL_ENUM_NAME(signature), may_be_java },

从源码分析可知,处java.lang.Class外还有一些类也会以同样的方式注入新的属性,如下:

#define CLASSLOADER_INJECTED_FIELDS(macro)                            \
  macro(java_lang_ClassLoader, loader_data,  intptr_signature, false)

#define MEMBERNAME_INJECTED_FIELDS(macro)                               \
  macro(java_lang_invoke_MemberName, vmloader, object_signature, false) \
  macro(java_lang_invoke_MemberName, vmindex,  intptr_signature, false) \
  macro(java_lang_invoke_MemberName, vmtarget, intptr_signature, false)

1.2、_offset_of_static_fields

      InstanceMirrorKlass就增加了一个静态属性_offset_of_static_fields,用来描述静态字段的起始偏移量,因为是静态的,无法在HSDB中直接查看该属性。该属性是通过init_offset_of_static_fields方法初始化的,其实现如下:

 static void init_offset_of_static_fields() {
    //_offset_of_static_fields是静态字段,未初始化时系统自动赋值0
    assert(_offset_of_static_fields == 0, "once");
    //SystemDictionary::Class_klass()就是全局唯一的InstanceMirrorKlass实例
    _offset_of_static_fields = InstanceMirrorKlass::cast(SystemDictionary::Class_klass())->size_helper() << LogHeapWordSize;
  }
  
int size_helper() const {
    return layout_helper_to_size_helper(layout_helper());
  }

static int layout_helper_to_size_helper(jint lh) {
    assert(lh > (jint)_lh_neutral_value, "must be instance");
    return lh >> LogHeapWordSize;
  }

int layout_helper() const            { return _layout_helper; }

InstanceMirrorKlass的_layout_helper的取值是105,如下:

因此_offset_of_static_fields的值就是104。从上一节的Class包含的字段属性来看,该类的实例按照对象头和属性算出来的大小应该是100,但是必须按照一个字段对应的字节数即8对齐,因此是104,_layout_helper的值是为了保证通过size_helper方法计算的实例大小能够不低于实际的大小。

该方法的调用链如下:

1.3 为什么从_offset_of_static_fields处开始遍历?

     _offset_of_static_fields描述的是静态字段的起始偏移量,并非静态引用类型字段的起始偏移量,为什么要从这个偏移处开始遍历了?答案是Class实例为了确保通用性,将静态的引用类型属性都放在了一起且是静态字段区域的起始位置,然后通过static_oop_field_count属性就可以准确的定位所包含的oop了,这个跟普通类的实例完全相反,普通类实例的引用类型属性都是放在实例内存区域的最后,下面以上述的测试用例来说明。

先在Stack Memory中找到变量a即Base.class的地址,如下图:

然后在CHSDB中查看该地址对应的对象,如下:

该实例的大小是128,这个大小不是通过sizeof得出来的,而是从该oop的oop_size属性中读取出来的,用mem查看接下来的128字节即16个字段的内存数据,如下:

因为intel存储数据时是按照小端存储的,所以最后4行的真实内存数据应该如下:

0x00000000d69d9d78: 0x00000003 00000000 
0x00000000d69d9d80: 0xd69d9dc0 d687bde0 
0x00000000d69d9d88: 0xd687be00 00000001 
0x00000000d69d9d90: 0x00000004 00000000 

倒数第四行就是偏移量为96的起始位置,0x00000003就是字段static_oop_field_count的值了,即当前oop包含的静态oop属性的个数为3。倒数第三行就是偏移量为104的起始位置,即从此处开始就是保存的静态字段了。0xd69d9dc0就是属性s的压缩指针,d687bde0就是属性a2的压缩指针,0xd687be00就是属性a3的压缩指针了,剩下的两个00000001和0x00000004就是属性a和a4了。

2、InstanceRefKlass

     InstanceRefKlass继承自InstanceKlass,用来表示java/lang/ref/Reference及其子类的Klass,该类没有新增属性,主要改写了用于调整对象指针的oop_adjust_pointers方法和引用遍历的方法,其中引用遍历的方法定义如下:

其实现如下:

ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DEFN)
ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DEFN)

#define InstanceRefKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)        \
                                                                                \
int InstanceRefKlass::                                                          \
oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) {                  \
  /* Get size before changing pointers */                                       \
  SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::irk);\
                                                                                \
  //遍历Reference实例自身的属性,实际只遍历其中的queue属性,其他属性都在下面的宏方法中遍历
  int size = InstanceKlass::oop_oop_iterate##nv_suffix(obj, closure);           \
                                                                                \
  if (UseCompressedOops) {                                                      \
    InstanceRefKlass_SPECIALIZED_OOP_ITERATE(narrowOop, nv_suffix, contains);   \
  } else {                                                                      \
    InstanceRefKlass_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, contains);         \
  }                                                                             \
}

//contains是一个模板方法,默认返回true
template <class T> bool contains(T *t) { return true; }

ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m)
ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m)

#define InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix)      \
                                                                                \
int InstanceRefKlass::                                                          \
oop_oop_iterate##nv_suffix##_m(oop obj,                                         \
                               OopClosureType* closure,                         \
                               MemRegion mr) {                                  \
  SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::irk);\
                                                                                \
  int size = InstanceKlass::oop_oop_iterate##nv_suffix##_m(obj, closure, mr);   \
  if (UseCompressedOops) {                                                      \
    InstanceRefKlass_SPECIALIZED_OOP_ITERATE(narrowOop, nv_suffix, mr.contains); \
  } else {                                                                      \
    InstanceRefKlass_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, mr.contains);      \
  }                                                                             \
}

ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN)
ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN)

#if INCLUDE_ALL_GCS
#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix) \
                                                                                \
int InstanceRefKlass::                                                          \
oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) {        \
  /* Get size before changing pointers */                                       \
  SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::irk);\
                                                                                \
  int size = InstanceKlass::oop_oop_iterate_backwards##nv_suffix(obj, closure); \
                                                                                \
  if (UseCompressedOops) {                                                      \
    InstanceRefKlass_SPECIALIZED_OOP_ITERATE(narrowOop, nv_suffix, contains);   \
  } else {                                                                      \
    InstanceRefKlass_SPECIALIZED_OOP_ITERATE(oop, nv_suffix, contains);         \
  }                                                                             \
}
#endif // INCLUDE_ALL_GCS

 上述三类方法的实现除调用父类InstanceKlass的对应方法外,最终都落脚到对宏InstanceRefKlass_SPECIALIZED_OOP_ITERATE的调用,其实现如下:


#define InstanceRefKlass_SPECIALIZED_OOP_ITERATE(T, nv_suffix, contains)        \
  //获取该实例的discovered属性地址
  T* disc_addr = (T*)java_lang_ref_Reference::discovered_addr(obj);             \
  if (closure->apply_to_weak_ref_discovered_field()) {                          \
    //如果需要遍历discovered属性
    closure->do_oop##nv_suffix(disc_addr);                                      \
  }                                                                             \
                                                                                \
  //获取该实例的referent属性地址                                                                              
  T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj);           \
  //读取对应的oop
  T heap_oop = oopDesc::load_heap_oop(referent_addr);                           \
  //获取ReferenceProcessor引用
  ReferenceProcessor* rp = closure->_ref_processor;                             \
  if (!oopDesc::is_null(heap_oop)) {                                            \
    //如果heap_oop非空,则将其解密成真实地址的oop
    oop referent = oopDesc::decode_heap_oop_not_null(heap_oop);                 \
    //如果referent的对象头没有GC打标,只有堆内存压缩的时候才会打标
    if (!referent->is_gc_marked() && (rp != NULL) &&                            \
        //将其加入到对应类型的DiscoveredList中,等待处理
        rp->discover_reference(obj, reference_type())) {                        \
      return size;                                                              \
    } else if (contains(referent_addr)) {                                       \
      //如果已经GC打标了,说明还有其他对象引用该oop,则将其视为根节点正常遍历
      SpecializationStats::record_do_oop_call##nv_suffix(SpecializationStats::irk);\
      closure->do_oop##nv_suffix(referent_addr);                                \
    }                                                                           \
  }                                                                             \
  //获取该实例的next属性的地址
  T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj);                   \
  //JDK8下为true,表示使用discovered字段来构成pending_list
  if (ReferenceProcessor::pending_list_uses_discovered_field()) {               \
    //获取next属性对应的oop
    T next_oop  = oopDesc::load_heap_oop(next_addr);                            \
    /* Treat discovered as normal oop, if ref is not "active" (next non-NULL) */\
    if (!oopDesc::is_null(next_oop) && contains(disc_addr)) {                   \
      //next属性非空,说明该实例已经被加入到ReferenceQueue中,此时discovered属性通常为null
      SpecializationStats::record_do_oop_call##nv_suffix(SpecializationStats::irk);\
      closure->do_oop##nv_suffix(disc_addr);                                    \
    }                                                                           \
  }                                                                          \
  /* treat next as normal oop */                                                \
  if (contains(next_addr)) {                                                    \
    SpecializationStats::record_do_oop_call##nv_suffix(SpecializationStats::irk); \
    //遍历next属性
    closure->do_oop##nv_suffix(next_addr);                                      \
  }                                                                             \
  return size;                                                                  \

//父类的方法
ReferenceType reference_type() const     { return (ReferenceType)_reference_type; }

//_pending_list_uses_discovered_field默认为false,表示是否使用discovered字段来构成pending_list
//是从JDK_Version信息中获取的,JDK8下为true
 static bool pending_list_uses_discovered_field() {
    return _pending_list_uses_discovered_field;
  }

Reference的相关属性的用途可以参考《Hotspot 对象引用Reference和Finalizer 源码解析》。理解上述逻辑的一个关键是,referent属性会不会作为Reference的引用类型属性在第一步的InstanceKlass::oop_oop_iterate方法中被遍历到,答案是不会,我们可以通过HSDB来查看Reference的OopMapBlock,先在Class Browser中搜索java.lang.ref.Reference,搜索结果的第一个就是我们期望的InstanceRefKlass了,其包含的属性及其偏移量如下:

总共6个属性,最后两个是静态属性,不会出现在Reference实例对应的oop中,接着在CHSDB中,用inspect命令查看该Klass,如下:

从输出中可以知道该类的大小是440字节即55字宽,vtable是9个字宽,itable是2个字宽,且OopMapBlock的字宽数为1,所以OopMapBlock对应的内存就是第67个字宽,执行mem 0x0000000016a95d28 67命令,最后一行的内存数据如下:

其中前4个字节就是OopMapBlock的count属性,值为1,后面的4个字节就是OopMapBlock的offset属性,置为16,即第一步的InstanceKlass::oop_oop_iterate方法只会遍历queue这一个属性,referent属性,next属性和discovered属性都是在InstanceRefKlass_SPECIALIZED_OOP_ITERATE中处理的。

3、ObjArrayKlass

      ObjArrayKlass继承自表示数组的ArrayKlass,用来表示对象数组或者二维数组的Klass,该Klass对应的oopDesc就是objArrayOopDesc。ArrayKlass中没有新增引用遍历的相关方法,只有ObjArrayKlass中有,其定义如下:

注意这里只改写了三类方法的定义,还有一类oop_oop_iterate_backwards方法,该方法使用Klass的默认实现,最终调用oop_oop_iterate方法完成遍历,ObjArrayKlass中该方法的实现如下:

oop_oop_iterate_v就是上面改写的三类方法中的其中一个。 这三类方法实现如下:

ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DEFN)
ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DEFN)

#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)           \
                                                                                \
int ObjArrayKlass::oop_oop_iterate##nv_suffix(oop obj,                          \
                                              OopClosureType* closure) {        \
  SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::oa); \
  //校验该实例是数组类型
  assert (obj->is_array(), "obj must be array");                                \
  objArrayOop a = objArrayOop(obj);                                             \
  //获取该数组实例的整体大小
  int size = a->object_size();                                                  \
  if_do_metadata_checked(closure, nv_suffix) {                                  \
    //遍历该对象数组的对象类型klass
    closure->do_klass##nv_suffix(obj->klass());                                 \
  }                                                                             \
  //遍历数组元素
  ObjArrayKlass_OOP_ITERATE(a, p, (closure)->do_oop##nv_suffix(p))              \
  return size;                                                                  \
}

int object_size()           { return object_size(length()); }

static int object_size(int length) {
    //获取数组元素部分的大小,单位是字宽
    uint asz = array_size(length);
    //再加上对象头的大小,计算完整的数组的大小
    uint osz = align_object_size(header_size() + asz);
    assert(osz >= asz,   "no overflow");
    assert((int)osz > 0, "no overflow");
    return (int)osz;
  }

  static int array_size(int length) {
    //heapOopSize表示堆内存中oop的大小,开启指针压缩下是4字节,不开启是8字节
    //HeapWordSize表示一个字宽的字节数,64位下是8
    const uint OopsPerHeapWord = HeapWordSize/heapOopSize;
    assert(OopsPerHeapWord >= 1 && (HeapWordSize % heapOopSize == 0),
           "Else the following (new) computation would be in error");
    uint res = ((uint)length + OopsPerHeapWord - 1)/OopsPerHeapWord;
    return res;
  }

#define ObjArrayKlass_OOP_ITERATE(a, p, do_oop)      \
  if (UseCompressedOops) {                           \
    ObjArrayKlass_SPECIALIZED_OOP_ITERATE(narrowOop, \
      a, p, do_oop)                                  \
  } else {                                           \
    ObjArrayKlass_SPECIALIZED_OOP_ITERATE(oop,       \
      a, p, do_oop)                                  \
  }

#define ObjArrayKlass_SPECIALIZED_OOP_ITERATE(T, a, p, do_oop) \
{                                   \
  T* p         = (T*)(a)->base();   \
  T* const end = p + (a)->length(); \
  //根据数组长度计算终止地址,遍历指定范围内的oop
  while (p < end) {                 \
    do_oop;                         \
    p++;                            \
  }                                 \
}

ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m)
ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m)

#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix)         \
                                                                                \
int ObjArrayKlass::oop_oop_iterate##nv_suffix##_m(oop obj,                      \
                                                  OopClosureType* closure,      \
                                                  MemRegion mr) {               \
  SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::oa); \
  assert(obj->is_array(), "obj must be array");                                 \
  objArrayOop a  = objArrayOop(obj);                                            \
  int size = a->object_size();                                                  \
  if_do_metadata_checked(closure, nv_suffix) {                                  \
    closure->do_klass##nv_suffix(a->klass());                                   \
  }                                                                             \
  ObjArrayKlass_BOUNDED_OOP_ITERATE(                                            \
    a, p, mr.start(), mr.end(), (closure)->do_oop##nv_suffix(p))                \
  return size;                                                                  \
}

#define ObjArrayKlass_BOUNDED_OOP_ITERATE(a, p, low, high, do_oop) \
  if (UseCompressedOops) {                                   \
    ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop, \
      a, p, low, high, do_oop)                               \
  } else {                                                   \
    ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop,       \
      a, p, low, high, do_oop)                               \
  }

#define ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(T, a, p, low, high, do_oop) \
{                                   \
  T* const l = (T*)(low);           \
  T* const h = (T*)(high);          \
  T* p       = (T*)(a)->base();     \
  T* end     = p + (a)->length();   \
  //遍历所有的在指定范围中的数组元素
  if (p < l) p = l;                 \
  if (end > h) end = h;             \
  while (p < end) {                 \
    do_oop;                         \
    ++p;                            \
  }                                 \
}

ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r)
ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r)

#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r(OopClosureType, nv_suffix)         \
                                                                                \
//start和end是指遍历的数组元素的起止索引                                                                                
int ObjArrayKlass::oop_oop_iterate_range##nv_suffix(oop obj,                    \
                                                  OopClosureType* closure,      \
                                                  int start, int end) {         \
  SpecializationStats::record_iterate_call##nv_suffix(SpecializationStats::oa); \
  assert(obj->is_array(), "obj must be array");                                 \
  objArrayOop a  = objArrayOop(obj);                                            \
  //获取该数组的大小
  int size = a->object_size();                                                  \
  if (UseCompressedOops) {                                                      \
    //获取start处元素的地址
    HeapWord* low = start == 0 ? (HeapWord*)a : (HeapWord*)a->obj_at_addr<narrowOop>(start);\
    //获取end处元素的地址
    HeapWord* high = (HeapWord*)((narrowOop*)a->base() + end);                  \
    MemRegion mr(low, high);                                                    \
    if_do_metadata_checked(closure, nv_suffix) {                                \
      closure->do_klass##nv_suffix(a->klass());                                 \
    }                                                                           \
    //遍历指定范围内的数组元素
    ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(narrowOop,                    \
      a, p, low, high, (closure)->do_oop##nv_suffix(p))                         \
  } else {                                                                      \
    HeapWord* low = start == 0 ? (HeapWord*)a : (HeapWord*)a->obj_at_addr<oop>(start);  \
    HeapWord* high = (HeapWord*)((oop*)a->base() + end);                        \
    MemRegion mr(low, high);                                                    \
    if_do_metadata_checked(closure, nv_suffix) {                                \
      /* SSS: Do we need to pass down mr here? */                               \
      closure->do_klass##nv_suffix(a->klass());                                 \
    }                                                                           \
    ObjArrayKlass_SPECIALIZED_BOUNDED_OOP_ITERATE(oop,                          \
      a, p, low, high, (closure)->do_oop##nv_suffix(p))                         \
  }                                                                             \
  return size;                                                                  \
}

 其实现整体上跟InstanceKlass一致,就是获取遍历的地址范围时由从OopMapBlock获取改成了从自身的数组基地址和元素个数获取。

4、oopDesc::adjust_pointers / follow_contents

     adjust_pointers用于调整引用类型属性使其指向新的对象地址,这个新的对象地址可能是对象promote产生的,也可能是堆空间压缩产生的;第二个方法是专为负责堆空间压缩的MarkSweep准备的,同样是用来遍历各引用类型属性。这两方法对引用类型属性的遍历逻辑和oopDesc::oop_iterate类方法基本一致,其实现如下:

 

其调用链如下:

 

Klass定义了这两方法,但是没有给出默认实现,现在来逐一探讨Klass各子类的实现。

4.1、InstanceKlass

int InstanceKlass::oop_adjust_pointers(oop obj) {
  int size = size_helper();
  InstanceKlass_OOP_MAP_ITERATE( \
    obj, \
    MarkSweep::adjust_pointer(p), \
    assert_is_in)
  return size;
}

//使用同样的遍历逻辑
#define InstanceKlass_OOP_MAP_ITERATE(obj, do_oop, assert_fn)            \
{                                                                        \
  /* Compute oopmap block range. The common case                         \
     is nonstatic_oop_map_size == 1. */                                  \
  OopMapBlock* map           = start_of_nonstatic_oop_maps();            \
  OopMapBlock* const end_map = map + nonstatic_oop_map_count();          \
  if (UseCompressedOops) {                                               \
    while (map < end_map) {                                              \
      InstanceKlass_SPECIALIZED_OOP_ITERATE(narrowOop,                   \
        obj->obj_field_addr<narrowOop>(map->offset()), map->count(),     \
        do_oop, assert_fn)                                               \
      ++map;                                                             \
    }                                                                    \
  } else {                                                               \
    while (map < end_map) {                                              \
      InstanceKlass_SPECIALIZED_OOP_ITERATE(oop,                         \
        obj->obj_field_addr<oop>(map->offset()), map->count(),           \
        do_oop, assert_fn)                                               \
      ++map;                                                             \
    }                                                                    \
  }                                                                      \
}

template <class T> inline void MarkSweep::adjust_pointer(T* p) {
  T heap_oop = oopDesc::load_heap_oop(p);
  if (!oopDesc::is_null(heap_oop)) {
    //获取p原来指向的对象obj,然后从对象头中获取新的对象地址new_obj
    oop obj     = oopDesc::decode_heap_oop_not_null(heap_oop);
    oop new_obj = oop(obj->mark()->decode_pointer());
    assert(new_obj != NULL ||                         // is forwarding ptr?
           obj->mark() == markOopDesc::prototype() || // not gc marked?
           (UseBiasedLocking && obj->mark()->has_bias_pattern()),
                                                      // not gc marked?
           "should be forwarded");
    if (new_obj != NULL) {
      //new_obj不为空,则修改p,让其指向新地址
      assert(Universe::heap()->is_in_reserved(new_obj),
             "should be in object space");
      oopDesc::encode_store_heap_oop_not_null(p, new_obj);
    }
  }
}

void InstanceKlass::oop_follow_contents(oop obj) {
  assert(obj != NULL, "can't follow the content of NULL object");
  MarkSweep::follow_klass(obj->klass());
  InstanceKlass_OOP_MAP_ITERATE( \
    obj, \
    MarkSweep::mark_and_push(p), \ //如果p没有在对象头中打标,则打标,如果对象头中包含有非初始化的信息,则保存对象头
    assert_is_in_closed_subset)
}

 4.2、InstanceClassLoaderKlass

        InstanceClassLoaderKlass继承自InstanceKlass,只改写了oop_follow_contents方法的实现了该ClassLoader实例对应的ClassLoaderData的遍历,如下:

4.3、InstanceMirrorKlass

      InstanceMirrorKlass继承自InstanceKlass,两个方法都改写了,增加了对静态字段的遍历处理,其实现如下:

int InstanceMirrorKlass::oop_adjust_pointers(oop obj) {
  int size = oop_size(obj);
  InstanceKlass::oop_adjust_pointers(obj);
  
  //遍历oop包含的静态oop字段
  InstanceMirrorKlass_OOP_ITERATE(                                                    \
    start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj),        \
    MarkSweep::adjust_pointer(p),                                                     \
    assert_nothing)
  return size;
}

void InstanceMirrorKlass::oop_follow_contents(oop obj) {
  InstanceKlass::oop_follow_contents(obj);

  //获取该Class实例对应的类Klass
  Klass* klass = java_lang_Class::as_Klass(obj);
  if (klass != NULL) {
    if (klass->oop_is_instance() && InstanceKlass::cast(klass)->is_anonymous()) {
      //如果是匿名类则使用follow_class_loader方法,因为匿名类没有对应的ClassLoader
      MarkSweep::follow_class_loader(klass->class_loader_data());
    } else {
      //底层还是遍历该Klass对应的ClassLoader实例
      MarkSweep::follow_klass(klass);
    }
  } else {
    //如果klass为空则是基本类型对应的class
    assert(java_lang_Class::is_primitive(obj), "Sanity check");
  }

  InstanceMirrorKlass_OOP_ITERATE(                                                    \
    start_of_static_fields(obj), java_lang_Class::static_oop_field_count(obj),        \
    MarkSweep::mark_and_push(p),                                                      \
    assert_is_in_closed_subset)
}

#define InstanceMirrorKlass_OOP_ITERATE(start_p, count,    \
                                  do_oop, assert_fn)       \
{                                                          \
  if (UseCompressedOops) {                                 \
    InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE(narrowOop, \
      start_p, count,                                      \
      do_oop, assert_fn)                                   \
  } else {                                                 \
    InstanceMirrorKlass_SPECIALIZED_OOP_ITERATE(oop,       \
      start_p, count,                                      \
      do_oop, assert_fn)                                   \
  }                                                        \
}

4.4、InstanceRefKlass

        InstanceRefKlass继承自InstanceKlass,两个方法都改写了,增加了referent属性,next属性和discovered属性的处理。

int InstanceRefKlass::oop_adjust_pointers(oop obj) {
  int size = size_helper();
  //对Reference类实例而言,该方法只处理queue一个属性
  InstanceKlass::oop_adjust_pointers(obj);

  //处理另外三个属性,即使可能为空
  if (UseCompressedOops) {
    specialized_oop_adjust_pointers<narrowOop>(this, obj);
  } else {
    specialized_oop_adjust_pointers<oop>(this, obj);
  }
  return size;
}

template <class T> void specialized_oop_adjust_pointers(InstanceRefKlass *ref, oop obj) {
  T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj);
  //处理referent属性
  MarkSweep::adjust_pointer(referent_addr);
  T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj);
  //处理next属性
  MarkSweep::adjust_pointer(next_addr);
  T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj);
  //处理discovered属性
  MarkSweep::adjust_pointer(discovered_addr);
}

void InstanceRefKlass::oop_follow_contents(oop obj) {
  if (UseCompressedOops) {
    specialized_oop_follow_contents<narrowOop>(this, obj);
  } else {
    specialized_oop_follow_contents<oop>(this, obj);
  }
}

template <class T>
void specialized_oop_follow_contents(InstanceRefKlass* ref, oop obj) {
  //获取referent属性对应的对象
  T* referent_addr = (T*)java_lang_ref_Reference::referent_addr(obj);
  T heap_oop = oopDesc::load_heap_oop(referent_addr);
 
  if (!oopDesc::is_null(heap_oop)) {
    //heap_oop解密
    oop referent = oopDesc::decode_heap_oop_not_null(heap_oop);
    if (!referent->is_gc_marked() &&
        MarkSweep::ref_processor()->discover_reference(obj, ref->reference_type())) {
      // 如果referent对象未打标,且成功将其加入到对应类型的DiscoverList中,调用父类的oop_follow_contents方法处理该Reference实例
      ref->InstanceKlass::oop_follow_contents(obj);
      return;
    } else {
      //如果已打标或者加入DiscoverList失败,则将referent对象作为普通的对象处理
      MarkSweep::mark_and_push(referent_addr);
    }
  }
  T* next_addr = (T*)java_lang_ref_Reference::next_addr(obj);
  //如果使用discovered属性来构成pending_list
  if (ReferenceProcessor::pending_list_uses_discovered_field()) {
    T  next_oop = oopDesc::load_heap_oop(next_addr);
    if (!oopDesc::is_null(next_oop)) {
      //如果next属性非空,则该Reference实例不是Active状态,处理其discovered属性
      T* discovered_addr = (T*)java_lang_ref_Reference::discovered_addr(obj);
      MarkSweep::mark_and_push(discovered_addr);
    }
  } else {

  }
  //处理next属性
  MarkSweep::mark_and_push(next_addr);
  ref->InstanceKlass::oop_follow_contents(obj);
}

4.6、TypeArrayKlass

      TypeArrayKlass实现了这两方法,不过是空实现,因为其没有包含任何oop,如下:

void TypeArrayKlass::oop_follow_contents(oop obj) {
  assert(obj->is_typeArray(),"must be a type array");
}

int TypeArrayKlass::oop_adjust_pointers(oop obj) {
  assert(obj->is_typeArray(),"must be a type array");
  typeArrayOop t = typeArrayOop(obj);
  return t->object_size();
}

4.7、ObjArrayKlass

      ObjArrayKlass实现了这两方法,增加了对数组元素oop的处理,如下:

int ObjArrayKlass::oop_adjust_pointers(oop obj) {
  assert(obj->is_objArray(), "obj must be obj array");
  objArrayOop a = objArrayOop(obj);
  //获取数组大小
  int size = a->object_size();
  ObjArrayKlass_OOP_ITERATE(a, p, MarkSweep::adjust_pointer(p))
  return size;
}

void ObjArrayKlass::oop_follow_contents(oop obj) {
  assert (obj->is_array(), "obj must be array");
  MarkSweep::follow_klass(obj->klass());
  if (UseCompressedOops) {
    objarray_follow_contents<narrowOop>(obj, 0);
  } else {
    objarray_follow_contents<oop>(obj, 0);
  }
}

template <class T>
void ObjArrayKlass::objarray_follow_contents(oop obj, int index) {
  objArrayOop a = objArrayOop(obj);
  const size_t len = size_t(a->length());
  const size_t beg_index = size_t(index);
  assert(beg_index < len || len == 0, "index too large");

  //ObjArrayMarkingStride的默认值是512,一次push的oop的数量不能超过该值
  const size_t stride = MIN2(len - beg_index, ObjArrayMarkingStride);
  const size_t end_index = beg_index + stride;
  T* const base = (T*)a->base();
  T* const beg = base + beg_index;
  T* const end = base + end_index;

  //将指定返回的oop push
  for (T* e = beg; e < end; e++) {
    MarkSweep::mark_and_push<T>(e);
  }

  if (end_index < len) {
    //还有未处理完的,则作为一个ObjArrayTask,后面继续push
    MarkSweep::push_objarray(a, end_index); // Push the continuation.
  }
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
垃圾回收器是一种自动化的内存管理机制,用于检测和回收不再使用的内存资源,以便重新分配给其他程序使用。G1(Garbage-First)垃圾回收器是Java HotSpot虚拟机中的一种垃圾回收器,下面是G1垃圾回收器的工作流程: 1. 初始标记(Initial Mark):该阶段会暂停应用程序的执行,并标记所有根对象直接引用的对象。这个过程很快,因为只标记那些直接与根对象相关的对象。 2. 并发标记(Concurrent Mark):在此阶段,应用程序和垃圾回收线程并发执行。垃圾回收线程标记从根对象开始,遍历整个对象图,并标记所有可达的对象。这个阶段可能会在应用程序运行时进行,并且不会停止应用程序的执行。 3. 最终标记(Final Mark):在并发标记阶段结束后,将再次暂停应用程序的执行,并完成剩余的标记工作。这个阶段主要标记在并发标记阶段还在使用但后续已不再使用的对象。 4. 筛选回收(Live Data Counting and Evacuation):G1会根据各个区域中存活数据的数量来设置优先级,并优先回收垃圾最多的区域。在筛选回收阶段,G1将未被引用的对象清理出堆空间,并将存活的对象复制到空闲的区域中。 5. 内存整理(Compaction):G1会对整个堆进行内存整理,目的是减少内存碎片化,提高内存利用率。在内存整理过程中,G1会将存活对象从一个或多个区域复制到一个连续的空闲区域。 总体来说,G1垃圾回收器通过标记、清理和整理的方式,有效地管理内存并进行垃圾回收。它具有可预测的停顿时间和高效的内存整理能力,适用于大型应用程序和需要更低停顿时间的场景。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值