jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

时间:2022-06-01 19:34:57

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

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

进入

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

这个p就是javathread打印看下

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析
$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
},

这个就是记录的最后一层的栈帧

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

这个就是对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对象

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

这个n 就是oopMap中类中的引用(oop)的个数,对每个oop进行判断,符合条件的进行从eden区域复制到to区域

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

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

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

看到了将拿到oop对象,进行判断obj->is_forwarded(),如果已经转移过了的oop对象,他的Mark值为转移后的oop地址,这种情况就不用copy直接返回值,那么看如何复制

jvm源码解读--13 gc_root中的栈中oop的mark 和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区域的了,比如

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

处理完本地变量表的还要出来操作数栈中的

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

处理完这个frame之后,获取下一个frame,通过函数fst.next();  void next()                     { if (!_is_done) _fr = _fr.sender(&_reg_map); }

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

对于新建frame的过程,参看开篇图片,进行新一轮循环,

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

这次不是解释器栈帧了,这次判断是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

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析

对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
}

jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析