zoukankan      html  css  js  c++  java
  • 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
    }
    View Code

    其中的成员变量为

      _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 "H213}؋u340203376f17204", 
        _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 "351N02", 
      _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
    }

  • 相关阅读:
    Windwos堆管理体系以及溢出利用
    Python利用ctypes实现C库函数调用
    Windows异常分发
    初探Windows用户态调试机制
    HTTP协议
    《格蠹汇编》调试笔记
    IDT系统中断描述表以及绕过Xurtr检测的HOOK姿势
    C++ 各种构造函数
    PsSetCreateProcessNotifyRoutineEx 创建回调函数
    导出函数与未导出函数
  • 原文地址:https://www.cnblogs.com/zytcomeon/p/14769251.html
Copyright © 2011-2022 走看看