12、jvm源码解读 - 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

&nbsp;

进入

&nbsp;

这个p就是javathread打印看下

&nbsp; &nbsp;

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

View Code

其中的成员变量为

  _anchor = {
    _last_Java_sp = 0x7f47891d56f0, 
    _last_Java_pc = 0x0, 
    _last_Java_fp = 0x7f47891d5740
  }, 

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

&nbsp;

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

&nbsp;

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

&nbsp;

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

&nbsp;

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

&nbsp;

这个就将新的新的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区域的了,比如

&nbsp;

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

&nbsp;

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

&nbsp;

&nbsp;

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

&nbsp;

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

&nbsp;

&nbsp;

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

&nbsp;