jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析
粘贴源码
package com.test; import java.util.Random; public class Test { static int number=12; private int age; private String name; public Test(int i, String string) { // TODO Auto-generated constructor stub this.age=i; this.name=string; } public Test() { // TODO Auto-generated constructor stub } public static void main(String[] args) { byte[][] useMemory = new byte[1000][]; Random random = new Random(); for (int i = 0; i < useMemory.length; i++) { useMemory[i] = new byte[1024 * 1024 * 10]; // 创建10M的对象 // 20%的概率将创建出来的对象变为可回收对象 if (random.nextInt(100) < 20) { System.out.println("created byte[] and set to null: " + i); useMemory[i] = null; } else { System.out.println("created byte[]: " + i); } } Test t2=new Test(); String str1="abc"; String str2 ="abc"; String str3=new String("abc"); boolean b1= str1==str2; boolean b2= str1==str3; // TODO Auto-generated method stub System.out.println("helloworld!"); Test t1=new Test(18,"jack"); System.gc(); System.out.println("gc finished ~"); System.out.println(number); } }
其中虚拟机参数(这个是调试虚拟机的参数,clion中的参数,注意点是com.test/Test放在最后
-XX:+UseSerialGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xmx200M -Xms200M -XX:NewRatio=3 -XX:SurvivorRatio=3 com.test/Test
解释:eden 30Mb,from 10Mb,to 10Mb
created byte[]: 0 created byte[]: 1 5804.490: [GC (Allocation Failure) 5804.493: [DefNew
当新建俩个对象20Mb的时候,发现eden分配空间不够,进行eden区域gc,
- 将eden和from区域的oop 根据gc_root依赖链条依次查找oop将找到的oop复制到to区域;
- 将gc_root中的指针有原来指向eden中的,指向to区域,gc_root包括,静态变量,线程中的栈帧中的对象
- 分析栈帧中的oop对象复制过程,先通过thread找到last_frame,最后的操作栈帧,这个比如就是Main方法的栈帧
- 通过oopMap找到13个oop对象,这个13个oop对象,一部分在locals本地变量表中,一部分在操作数栈中,那么就进行13次循环,进行13次辅助,
- 完成这个栈帧,通过fp成员变量,新建新的frame对象,再进行这个方法的分析
从thread:process_strong_roots:oops_do
进入
这个p就是javathread打印看下
$105 = (JavaThread *) 0x7f478000b800 (gdb) p * p $106 = (JavaThread) { <Thread> = { <ThreadShadow> = { <CHeapObj<512u>> = { <AllocatedObj> = { _vptr.AllocatedObj = 0x7f4788517390 <vtable for JavaThread+16> }, <No data fields>}, members of ThreadShadow: _pending_exception = 0x0, _exception_file = 0x0, _exception_line = 0 }, members of Thread: _real_malloc_address = 0x7f478000b268, _SR_lock = 0x7f478000c418, _suspend_flags = 0, _num_nested_signal = 0, _active_handles = 0x7f47800bb538, _free_handle_block = 0x7f47800d4a98, _last_handle_mark = 0x7f47891d52d0, _oops_do_parity = 0, _allow_safepoint_count = 0, _allow_allocation_count = 0, _skip_gcalot = true, _tlab = { <CHeapObj<512u>> = { <AllocatedObj> = { _vptr.AllocatedObj = 0x7f4788517710 <vtable for ThreadLocalAllocBuffer+16> }, <No data fields>}, members of ThreadLocalAllocBuffer: _start = 0x0, _top = 0x0, _pf_top = 0x0, _end = 0x0, _desired_size = 78643, _refill_waste_limit = 1240, static _target_refills = 50, _number_of_refills = 0, _fast_refill_waste = 0, _slow_refill_waste = 0, _gc_waste = 0, _slow_allocations = 0, _allocation_fraction = { <CHeapObj<1280u>> = { <AllocatedObj> = { _vptr.AllocatedObj = 0x7f47885059d0 <vtable for AdaptiveWeightedAverage+16> }, <No data fields>}, members of AdaptiveWeightedAverage: _average = 0.513759971, _sample_count = 2, _weight = 35, _is_old = false, static OLD_THRESHOLD = 100, _last_sample = 0.0275225826 }, static _global_stats = 0x7f4780023758 }, _allocated_bytes = 21532896, _trace_data = {<No data fields>}, _vm_operation_started_count = 1, _vm_operation_completed_count = 0, _current_pending_monitor = 0x0, _current_pending_monitor_is_from_java = true, _current_waiting_monitor = 0x0, omFreeList = 0x7f4764004d90, omFreeCount = 31, omFreeProvision = 49, omInUseList = 0x0, omInUseCount = 0, _visited_for_critical_count = true, _osthread = 0x7f478000d188, _resource_area = 0x7f478000a338, _current_resource_mark = 0x7f47891d5af0, _handle_area = 0x7f478000c078, _metadata_handles = 0x7f478000c218, _stack_base = 0x7f47891d7000 "", _stack_size = 1048576, _self_raw_id = 0, _lgrp_id = -1, _owned_locks = 0x7f4780008988, _jvmti_env_iteration_count = 0, _Stalled = 0, _TypeTag = 11181, _ParkEvent = 0x7f478000c500, _SleepEvent = 0x7f478000c800, _MutexEvent = 0x7f478000ca00, _MuxEvent = 0x7f478000cc00, NativeSyncRecursion = -235802127, _OnTrap = 0, _hashStateW = 1442407170, _hashStateX = -2029131186, _hashStateY = 1550089733, _hashStateZ = -1282369710, _schedctl = 0x0, rng = {989922723, -235802127, -235802127, -235802127} }, members of JavaThread: _next = 0x0, _threadObj = 0xf3804ec0, _java_call_counter = 1, _anchor = { _last_Java_sp = 0x7f47891d56f0, _last_Java_pc = 0x0, _last_Java_fp = 0x7f47891d5740 }, _entry_point = 0x0, _jni_environment = { functions = 0x7f478852dba0 <jni_NativeInterface> }, _deopt_mark = 0x0, _must_deopt_id = 0x0, _deopt_nmethod = 0x0, _vframe_array_head = 0x0, _vframe_array_last = 0x0, _deferred_locals_updates = 0x0, _callee_target = 0x7f4785290f98, _vm_result = 0x0, _vm_result_2 = 0x0, _deferred_card_mark = { _start = 0x0, _word_size = 0 }, _monitor_chunks = 0x0, _special_runtime_exit_condition = JavaThread::_no_async_condition, _pending_async_exception = 0x0, _thread_state = _thread_blocked, _safepoint_state = 0x7f478000cf98, _saved_exception_pc = 0x0, _terminated = JavaThread::_not_terminated, _suspend_equivalent = false, _in_deopt_handler = 0, _doing_unsafe_access = false, _do_not_unlock_if_synchronized = false, _jni_attach_state = JavaThread::_not_attaching_via_jni, _stack_guard_state = JavaThread::stack_guard_enabled, _exception_oop = 0x0, _exception_pc = 0x0, _exception_handler_pc = 0x0, _is_method_handle_return = 0, _jni_active_critical = 0, _depth_first_number = -235802127, _popframe_condition = 0, _jmp_ring_index = 0, _jmp_ring = {{ _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }, { _target = 0, _instruction = 0, _file = 0x0, _line = 0 }}, _satb_mark_queue = { <PtrQueue> = { _vptr.PtrQueue = 0x7f4788515070 <vtable for ObjPtrQueue+16>, _qset = 0x7f47885c00e0 <JavaThread::_satb_mark_queue_set>, _active = false, _buf = 0x0, _index = 0, _sz = 17433981653976478193, _perm = false, _lock = 0x0 }, <No data fields>}, static _satb_mark_queue_set = { <PtrQueueSet> = { _vptr.PtrQueueSet = 0x7f4788515090 <vtable for SATBMarkQueueSet+16>, _cbl_mon = 0x0, _completed_buffers_head = 0x0, _completed_buffers_tail = 0x0, _n_completed_buffers = 0, _process_completed_threshold = 0, _process_completed = false, _fl_lock = 0x0, _buf_free_list = 0x0, _buf_free_list_sz = 0, _fl_owner = 0x7f47885c00e0 <JavaThread::_satb_mark_queue_set>, _sz = 0, _all_active = false, _notify_when_complete = false, _max_completed_queue = 0, _completed_queue_padding = 0 }, members of SATBMarkQueueSet: _closure = 0x0, _par_closures = 0x0, _shared_satb_queue = { <PtrQueue> = { _vptr.PtrQueue = 0x7f4788515070 <vtable for ObjPtrQueue+16>, _qset = 0x7f47885c00e0 <JavaThread::_satb_mark_queue_set>, _active = false, _buf = 0x0, _index = 0, _sz = 0, _perm = true, _lock = 0x0 }, <No data fields>} }, _dirty_card_queue = { <PtrQueue> = { _vptr.PtrQueue = 0x7f4788501430 <vtable for DirtyCardQueue+16>, _qset = 0x7f47885c01a0 <JavaThread::_dirty_card_queue_set>, _active = true, _buf = 0x0, _index = 0, _sz = 17433981653976478193, _perm = false, _lock = 0x0 }, <No data fields>}, static _dirty_card_queue_set = { <PtrQueueSet> = { _vptr.PtrQueueSet = 0x7f4788501410 <vtable for DirtyCardQueueSet+16>, _cbl_mon = 0x0, _completed_buffers_head = 0x0, _completed_buffers_tail = 0x0, _n_completed_buffers = 0, _process_completed_threshold = 0, _process_completed = false, _fl_lock = 0x0, _buf_free_list = 0x0, _buf_free_list_sz = 0, _fl_owner = 0x7f47885c01a0 <JavaThread::_dirty_card_queue_set>, _sz = 0, _all_active = true, _notify_when_complete = true, _max_completed_queue = 0, _completed_queue_padding = 0 }, members of DirtyCardQueueSet: _closure = 0x0, _shared_dirty_card_queue = { <PtrQueue> = { _vptr.PtrQueue = 0x7f4788501430 <vtable for DirtyCardQueue+16>, _qset = 0x7f47885c01a0 <JavaThread::_dirty_card_queue_set>, _active = true, _buf = 0x0, _index = 0, _sz = 0, _perm = true, _lock = 0x0 }, <No data fields>}, _free_ids = 0x0, _processed_buffers_mut = 0, _processed_buffers_rs_thread = 0 }, _recorder = 0x0, _thread_profiler = 0x0, _safepoint_visible = true, _privileged_stack_top = 0x0, _array_for_gc = 0x0, _popframe_preserved_args = 0x0, _popframe_preserved_args_size = 0, _jvmti_thread_state = 0x0, _jvmti_get_loaded_classes_closure = 0x0, _interp_only_mode = 0, _should_post_on_exceptions_flag = 0, _thread_stat = 0x7f478000cd68, static _stack_size_at_create = 1048576, _blocked_on_compilation = false, _parker = 0x7f478000ceb8, _cached_monitor_info = 0x0, _claimed_par_id = -1 }
其中的成员变量为
_anchor = { _last_Java_sp = 0x7f47891d56f0, _last_Java_pc = 0x0, _last_Java_fp = 0x7f47891d5740 },
这个就是记录的最后一层的栈帧
这个就是对frame的处理函数
那么调用的就是fst.current(),
(gdb) p fst $107 = (StackFrameStream) { <StackObj> = { <AllocatedObj> = { _vptr.AllocatedObj = 0x7f4788501fd0 <vtable for StackFrameStream+16> }, <No data fields>}, members of StackFrameStream: _fr = { _sp = 0x7f47891d5750, _pc = 0x7f4771000671 "H\213}؋u\340\203\376\f\017\204", _cb = 0x7f47710003d0, _deopt_state = frame::not_deoptimized, static _check_value = { <OopClosure> = { <Closure> = { <StackObj> = { <AllocatedObj> = { _vptr.AllocatedObj = 0x7f4788501d90 <vtable for frame::CheckValueClosure+16> }, <No data fields>}, members of Closure: _abort = false }, <No data fields>}, <No data fields>}, static _check_oop = { <OopClosure> = { <Closure> = { <StackObj> = { <AllocatedObj> = { _vptr.AllocatedObj = 0x7f4788501d50 <vtable for frame::CheckOopClosure+16> }, <No data fields>}, members of Closure: _abort = false }, <No data fields>}, <No data fields>}, static _zap_dead = { <OopClosure> = { <Closure> = { <StackObj> = { <AllocatedObj> = { _vptr.AllocatedObj = 0x7f4788501d10 <vtable for frame::ZapDeadClosure+16> }, <No data fields>}, members of Closure: _abort = false }, <No data fields>}, <No data fields>}, _fp = 0x7f47891d5800, _unextended_sp = 0x7f47891d5798 }, _reg_map = { <StackObj> = { <AllocatedObj> = { _vptr.AllocatedObj = 0x7f4788501f90 <vtable for RegisterMap+16> }, <No data fields>}, members of RegisterMap: _location = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7f47891d5740, 0x7f47891d5740, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, _location_valid = {3072, 0, 0}, _include_argument_oops = false, _thread = 0x7f478000b800, _update_map = true, _update_for_id = 0x0 }, _is_done = true }
那么,返回的就是_fr对象
// Iteration bool is_done() { return (_is_done) ? true : (_is_done = _fr.is_first_frame(), false); } void next() { if (!_is_done) _fr = _fr.sender(&_reg_map); } // Query frame *current() { return &_fr; } RegisterMap* register_map() { return &_reg_map; }
对于构造函数fst的成员_fr是这样的
StackFrameStream::StackFrameStream(JavaThread *thread, bool update) : _reg_map(thread, update) { assert(thread->has_last_Java_frame(), "sanity check"); _fr = thread->last_frame(); _is_done = false; }
// Accessing frames
frame last_frame() {
_anchor.make_walkable(this);
return pd_last_frame();
}
frame pd_last_frame() {
assert(has_last_Java_frame(), "must have last_Java_sp() when suspended");
if (_anchor.last_Java_pc() != NULL) {
return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc());
} else {
// This will pick up pc from sp
return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp());
}
}
这样子就是用_anchor的信息新建了第一frame,打印一下这个frame
(gdb) p _fr._sp $82 = (intptr_t *) 0x7f47891d56f0 (gdb) p * _fr $83 = { _sp = 0x7f47891d56f0, //栈顶 _pc = 0x7f4771044e53 "\351N\002", _cb = 0x7f4771005390, _deopt_state = frame::not_deoptimized, static _check_value = { <OopClosure> = { <Closure> = { <StackObj> = { <AllocatedObj> = { _vptr.AllocatedObj = 0x7f4788501d90 <vtable for frame::CheckValueClosure+16> }, <No data fields>}, members of Closure: _abort = false }, <No data fields>}, <No data fields>}, static _check_oop = { <OopClosure> = { <Closure> = { <StackObj> = { <AllocatedObj> = { _vptr.AllocatedObj = 0x7f4788501d50 <vtable for frame::CheckOopClosure+16> }, <No data fields>}, members of Closure: _abort = false }, <No data fields>}, <No data fields>}, static _zap_dead = { <OopClosure> = { <Closure> = { <StackObj> = { <AllocatedObj> = { _vptr.AllocatedObj = 0x7f4788501d10 <vtable for frame::ZapDeadClosure+16> }, <No data fields>}, members of Closure: _abort = false }, <No data fields>}, <No data fields>}, _fp = 0x7f47891d5740, _unextended_sp = 0x7f47891d56f0 }
这个frame的具体对应内存数值,在开篇的图片中,其最重要的信息就是_fp,这个是其他内容的定位基准
接着进行
// Memory management void oops_do(OopClosure* f, CLDToOopClosure* cld_f, CodeBlobClosure* cf, RegisterMap* map) { oops_do_internal(f, cld_f, cf, map, true); } ==> if (is_interpreted_frame()) { oops_interpreted_do(f, cld_f, map, use_interpreter_oop_map_cache); } else if (is_entry_frame()) { oops_entry_do(f, map);
进入
void frame::oops_interpreted_do(OopClosure* f, CLDToOopClosure* cld_f, const RegisterMap* map, bool query_oop_map_cache) { assert(is_interpreted_frame(), "Not an interpreted frame"); assert(map != NULL, "map must be set"); Thread *thread = Thread::current(); methodHandle m (thread, interpreter_frame_method()); jint bci = interpreter_frame_bci(); assert(!Universe::heap()->is_in(m()), "must be valid oop"); assert(m->is_method(), "checking frame value"); assert((m->is_native() && bci == 0) || (!m->is_native() && bci >= 0 && bci < m->code_size()), "invalid bci value"); // Handle the monitor elements in the activation for ( BasicObjectLock* current = interpreter_frame_monitor_end(); current < interpreter_frame_monitor_begin(); current = next_monitor_in_interpreter_frame(current) ) { #ifdef ASSERT interpreter_frame_verify_monitor(current); #endif current->oops_do(f); } // process fixed part if (cld_f != NULL) { // The method pointer in the frame might be the only path to the method's // klass, and the klass needs to be kept alive while executing. The GCs // don't trace through method pointers, so typically in similar situations // the mirror or the class loader of the klass are installed as a GC root. // To minimze the overhead of doing that here, we ask the GC to pass down a // closure that knows how to keep klasses alive given a ClassLoaderData. cld_f->do_cld(m->method_holder()->class_loader_data()); } #if !defined(PPC) || defined(ZERO) if (m->is_native()) { #ifdef CC_INTERP interpreterState istate = get_interpreterState(); f->do_oop((oop*)&istate->_oop_temp); #else f->do_oop((oop*)( fp() + interpreter_frame_oop_temp_offset )); #endif /* CC_INTERP */ } #else // PPC if (m->is_native() && m->is_static()) { f->do_oop(interpreter_frame_mirror_addr()); } #endif // PPC int max_locals = m->is_native() ? m->size_of_parameters() : m->max_locals(); Symbol* signature = NULL; bool has_receiver = false; // Process a callee's arguments if we are at a call site // (i.e., if we are at an invoke bytecode) // This is used sometimes for calling into the VM, not for another // interpreted or compiled frame. if (!m->is_native()) { Bytecode_invoke call = Bytecode_invoke_check(m, bci); if (call.is_valid()) { signature = call.signature(); has_receiver = call.has_receiver(); if (map->include_argument_oops() && interpreter_frame_expression_stack_size() > 0) { ResourceMark rm(thread); // is this right ??? // we are at a call site & the expression stack is not empty // => process callee's arguments // // Note: The expression stack can be empty if an exception // occurred during method resolution/execution. In all // cases we empty the expression stack completely be- // fore handling the exception (the exception handling // code in the interpreter calls a blocking runtime // routine which can cause this code to be executed). // (was bug gri 7/27/98) oops_interpreted_arguments_do(signature, has_receiver, f); } } } InterpreterFrameClosure blk(this, max_locals, m->max_stack(), f); // process locals & expression stack InterpreterOopMap mask; if (query_oop_map_cache) { m->mask_for(bci, &mask); } else { OopMapCache::compute_one_oop_map(m, bci, &mask); } mask.iterate_oop(&blk); }
直接进入最后3行,这个mask就是oopMap对象
这个n 就是oopMap中类中的引用(oop)的个数,对每个oop进行判断,符合条件的进行从eden区域复制到to区域
addr = (oop*) _fr->interpreter_frame_local_at(offset);这个是对于本地变量表中的oop对象进行取值
intptr_t* frame::interpreter_frame_local_at(int index) const { const int n = Interpreter::local_offset_in_bytes(index)/wordSize; return &((*interpreter_frame_locals_addr())[n]); }
void ScanClosure::do_oop(narrowOop* p) { ScanClosure::do_oop_work(p); }
看到了将拿到oop对象,进行判断obj->is_forwarded(),如果已经转移过了的oop对象,他的Mark值为转移后的oop地址,这种情况就不用copy直接返回值,那么看如何复制
这个就将新的新的oop对象复制到了to区域
将返回的obj赋值给p地址的内容
// Encode and store a heap oop. inline void oopDesc::encode_store_heap_oop_not_null(narrowOop* p, oop v) { *p = encode_heap_oop_not_null(v); } inline narrowOop oopDesc::encode_heap_oop_not_null(oop v) { assert(!is_null(v), "oop value can never be zero"); assert(check_obj_alignment(v), "Address not aligned"); assert(Universe::heap()->is_in_reserved(v), "Address not in heap"); address base = Universe::narrow_oop_base(); int shift = Universe::narrow_oop_shift(); uint64_t pd = (uint64_t)(pointer_delta((void*)v, (void*)base, 1)); assert(OopEncodingHeapMax > pd, "change encoding max if new encoding"); uint64_t result = pd >> shift; assert((result & CONST64(0xffffffff00000000)) == 0, "narrow oop overflow"); assert(decode_heap_oop(result) == v, "reversibility"); return (narrowOop)result; }
那么原来的p地址,p就是栈帧的地址,中的内容由在eden 指向了to区域的了,比如
处理完本地变量表的还要出来操作数栈中的
处理完这个frame之后,获取下一个frame,通过函数fst.next(); void next() { if (!_is_done) _fr = _fr.sender(&_reg_map); }
对于新建frame的过程,参看开篇图片,进行新一轮循环,
这次不是解释器栈帧了,这次判断是callstub栈帧了,那么
void frame::oops_entry_do(OopClosure* f, const RegisterMap* map) { assert(map != NULL, "map must be set"); if (map->include_argument_oops()) { // must collect argument oops, as nobody else is doing it Thread *thread = Thread::current(); methodHandle m (thread, entry_frame_call_wrapper()->callee_method()); EntryFrameOopFinder finder(this, m->signature(), m->is_static()); finder.arguments_do(f); } // Traverse the Handle Block saved in the entry frame entry_frame_call_wrapper()->oops_do(f); }
JavaCallWrapper* entry_frame_call_wrapper() const { return *entry_frame_call_wrapper_addr(); }
// Entry frames
inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const {
return (JavaCallWrapper**)addr_at(entry_frame_call_wrapper_offset);
}
intptr_t* addr_at(int index) const { return &fp()[index]; }
这是要找的callwrapper
对result进行判断,本次执行为null,那么不处理
,还对javaCallWrapper的_handles进行处理
(gdb) p _handles $110 = (JNIHandleBlock *) 0x7f478000d018 (gdb) p * _handles $111 = (JNIHandleBlock) { <CHeapObj<1792u>> = { <AllocatedObj> = { _vptr.AllocatedObj = 0x7f4788509e30 <vtable for JNIHandleBlock+16> }, <No data fields>}, members of JNIHandleBlock: _handles = {0xf3843850, 0xf3803600, 0xf3843d60, 0xf3886088, 0xf3886088, 0xf3800830, 0xf3886708, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe, 0xfefefefefefefefe}, _top = 7, _next = 0x0, _last = 0x7f478000d018, _pop_frame_link = 0x0, _free_list = 0x0, _allocate_before_rebuild = 0, _block_list_link = 0x0, static _block_list = 0x7f4780165dc8, static _block_free_list = 0x0, static _blocks_allocated = 33 }