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 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(二) 源码解析相关推荐
- Hotspot 垃圾回收之oop_iterate(一) 源码解析
目录 1.oopDesc::oop_iterate/ oopDesc::oop_iterate_backwards 2.Klass::oop_oop_iterate / Klass::oop_oop_ ...
- Hotspot 对象引用Reference和Finalizer 源码解析
目录 一.Reference 1.SoftReference / WeakReference / PhantomReference 2.定义 3.ReferenceHandler 4.Cleaner ...
- Hotspot 垃圾回收之ReferenceProcessor(二) 源码解析
目录 1.process_discovered_reflist 2.process_phaseJNI 3.process_discovered_references 4.preclean_discov ...
- Hotspot 垃圾回收之GenCollectedHeap 源码解析
目录 1.定义 2.构造方法 / initialize / post_initialize 3.do_collection 4.do_full_collection 5.collect 6.VM_Ge ...
- Hotspot 垃圾回收之VM_Operation 源码解析
目录 一.VM_Operation 二.VMThread 1.定义 2.create / destroy 3.run / wait_for_vm_thread_exit 4.loop 5.VMThr ...
- Hotspot 重量级锁ObjectMonitor(二) 源码解析
目录 1.AddWaiter / DequeueWaiter /DequeueSpecificWaiter 2.wait 3.notify 4.notifyAll 5.exit 6.try_enter ...
- 小程序源码:登录已修复零象垃圾废品回收微信小程序源码下载,V2.8.2完整全开源前端+后端
零象垃圾废品回收小程序源码,V2.8.2完整全开源安装包+小程序前端, 是一款专注于垃圾回收小程序源码,支持协议定期企业废品回收,垃圾分类小区物业定期回收. 关于程序 运行环境:微擎+PHP+MYSQ ...
- Hotspot 重量级锁ObjectMonitor(一) 源码解析
目录 1.定义 2.TrySpin_VaryDuration 3.ObjectWaiter 4.EnterI 5.JavaThreadBlockedOnMonitorEnterState / OSTh ...
- 【vuejs深入三】vue源码解析之二 htmlParse解析器的实现
写在前面 一个好的架构需要经过血与火的历练,一个好的工程师需要经过无数项目的摧残. 昨天博主分析了一下在vue中,最为基础核心的api,parse函数,它的作用是将vue的模板字符串转换成ast,从而 ...
最新文章
- [python数据分析] 简述幂率定律及绘制Power-law函数
- ZOJ1027 Travelling Fee(DP+SPFA)
- pyDes 实现 Python 版的 DES 对称加密/解密--转
- android服务器概念,Android_tv_metro
- wincc 关闭弹出窗口C语言,退出WINCC操作画面时弹出对话框要求输入用户名和密码-工业支持中心-西门子中国...
- scala 连接oracle_一分钟教你学会用java连接Oracle数据库
- JS事件循环机制:同步与异步任务 之 宏任务 微任务
- JavaScript--我所理解的原型链
- [Xilinx]Xilinx ISE14.2中调用文本编辑器NotePad++设置方法
- iview 路由权限判断的处理
- matlab2c使用c++实现matlab函数系列教程-toeplitz函数
- 设计模式12——代理模式
- 关于SQL中Between语句查询日期的问题
- 福昕高级PDF 专业版程序安装及注意事项
- Flutter 绝对定位 轮播图背景色
- 常见文件文件头文件尾格式总结及各类文件头
- C语言实现任何文件的加密解密
- 利用metadata-extractor定向获取图片拍摄时间以及宽高
- 利用Python删除Android项目中未使用的layout
- Java ArrayList集合案例(上课笔记)