目录

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 fieldsreturn 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一致则增加countcount++;                                                       \//如果start未初始化,则初始化,表示数组的起始位置if (start == -1) start = klass##_##name##_enum;                \}ALL_INJECTED_FIELDS(LOOKUP_INJECTED_FIELD);
#undef LOOKUP_INJECTED_FIELDif (start != -1) {//如果找到了,将field_count置为count*field_count = count;//返回_injected_fields数组中start处开始的元素,元素个数就是countreturn _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是静态字段,未初始化时系统自动赋值0assert(_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);           \//读取对应的oopT heap_oop = oopDesc::load_heap_oop(referent_addr);                           \//获取ReferenceProcessor引用ReferenceProcessor* rp = closure->_ref_processor;                             \if (!oopDesc::is_null(heap_oop)) {                                            \//如果heap_oop非空,则将其解密成真实地址的oopoop 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_listif (ReferenceProcessor::pending_list_uses_discovered_field()) {               \//获取next属性对应的oopT 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属性通常为nullSpecializationStats::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下为truestatic 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) {                                  \//遍历该对象数组的对象类型klassclosure->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位下是8const 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(); \//根据数组长度计算终止地址,遍历指定范围内的oopwhile (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_objoop 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实例对应的类KlassKlass* klass = java_lang_Class::as_Klass(obj);if (klass != NULL) {if (klass->oop_is_instance() && InstanceKlass::cast(klass)->is_anonymous()) {//如果是匿名类则使用follow_class_loader方法,因为匿名类没有对应的ClassLoaderMarkSweep::follow_class_loader(klass->class_loader_data());} else {//底层还是遍历该Klass对应的ClassLoader实例MarkSweep::follow_klass(klass);}} else {//如果klass为空则是基本类型对应的classassert(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_listif (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 pushfor (T* e = beg; e < end; e++) {MarkSweep::mark_and_push<T>(e);}if (end_index < len) {//还有未处理完的,则作为一个ObjArrayTask,后面继续pushMarkSweep::push_objarray(a, end_index); // Push the continuation.}
}

Hotspot 垃圾回收之oop_iterate(二) 源码解析相关推荐

  1. Hotspot 垃圾回收之oop_iterate(一) 源码解析

    目录 1.oopDesc::oop_iterate/ oopDesc::oop_iterate_backwards 2.Klass::oop_oop_iterate / Klass::oop_oop_ ...

  2. Hotspot 对象引用Reference和Finalizer 源码解析

    目录 一.Reference 1.SoftReference / WeakReference / PhantomReference 2.定义 3.ReferenceHandler 4.Cleaner ...

  3. Hotspot 垃圾回收之ReferenceProcessor(二) 源码解析

    目录 1.process_discovered_reflist 2.process_phaseJNI 3.process_discovered_references 4.preclean_discov ...

  4. Hotspot 垃圾回收之GenCollectedHeap 源码解析

    目录 1.定义 2.构造方法 / initialize / post_initialize 3.do_collection 4.do_full_collection 5.collect 6.VM_Ge ...

  5. Hotspot 垃圾回收之VM_Operation 源码解析

    目录 一.VM_Operation ​二.VMThread 1.定义 2.create / destroy 3.run / wait_for_vm_thread_exit 4.loop 5.VMThr ...

  6. Hotspot 重量级锁ObjectMonitor(二) 源码解析

    目录 1.AddWaiter / DequeueWaiter /DequeueSpecificWaiter 2.wait 3.notify 4.notifyAll 5.exit 6.try_enter ...

  7. 小程序源码:登录已修复零象垃圾废品回收微信小程序源码下载,V2.8.2完整全开源前端+后端

    零象垃圾废品回收小程序源码,V2.8.2完整全开源安装包+小程序前端, 是一款专注于垃圾回收小程序源码,支持协议定期企业废品回收,垃圾分类小区物业定期回收. 关于程序 运行环境:微擎+PHP+MYSQ ...

  8. Hotspot 重量级锁ObjectMonitor(一) 源码解析

    目录 1.定义 2.TrySpin_VaryDuration 3.ObjectWaiter 4.EnterI 5.JavaThreadBlockedOnMonitorEnterState / OSTh ...

  9. 【vuejs深入三】vue源码解析之二 htmlParse解析器的实现

    写在前面 一个好的架构需要经过血与火的历练,一个好的工程师需要经过无数项目的摧残. 昨天博主分析了一下在vue中,最为基础核心的api,parse函数,它的作用是将vue的模板字符串转换成ast,从而 ...

最新文章

  1. [python数据分析] 简述幂率定律及绘制Power-law函数
  2. ZOJ1027 Travelling Fee(DP+SPFA)
  3. pyDes 实现 Python 版的 DES 对称加密/解密--转
  4. android服务器概念,Android_tv_metro
  5. wincc 关闭弹出窗口C语言,退出WINCC操作画面时弹出对话框要求输入用户名和密码-工业支持中心-西门子中国...
  6. scala 连接oracle_一分钟教你学会用java连接Oracle数据库
  7. JS事件循环机制:同步与异步任务 之 宏任务 微任务
  8. JavaScript--我所理解的原型链
  9. [Xilinx]Xilinx ISE14.2中调用文本编辑器NotePad++设置方法
  10. iview 路由权限判断的处理
  11. matlab2c使用c++实现matlab函数系列教程-toeplitz函数
  12. 设计模式12——代理模式
  13. 关于SQL中Between语句查询日期的问题
  14. 福昕高级PDF 专业版程序安装及注意事项
  15. Flutter 绝对定位 轮播图背景色
  16. 常见文件文件头文件尾格式总结及各类文件头
  17. C语言实现任何文件的加密解密
  18. 利用metadata-extractor定向获取图片拍摄时间以及宽高
  19. 利用Python删除Android项目中未使用的layout
  20. Java ArrayList集合案例(上课笔记)

热门文章

  1. java编写测试类test,已获万赞
  2. 软件项目管理 8.4.软件项目质量计划
  3. 以太网性能测试仪的误码测试
  4. lua 文件系统操作
  5. 怎么将计算机工具栏时间去除,电脑时间显示怎么去掉上午下午
  6. 【AWK用法】https://www.cnblogs.com/lizhouwei/p/10029505.html
  7. git-将分支合并到主分支
  8. Shell 中的颜色
  9. 2017年第八届蓝桥杯C/C++B组省赛题目解析
  10. 浅谈海外游戏多语言版本的实现