Hotspot 方法调用之HandleMark 源码解析

目录一、HandleMark1、定义2、构造和析构方法二、HandleArea三、CHeapObj四、Area1、定义2、Amalloc方法3、destruct_contents方法4、contains方法五、Chunk1、定义2、new和delete重载3、chop和next_chop方法六、ChunkPool1、定义2、...
摘要由CSDN通过智能技术生成

  目录

一、HandleMark

1、定义

2、构造和析构方法

二、HandleArea

三、CHeapObj

四、Area

1、定义

 2、Amalloc方法

3、destruct_contents方法

4、contains方法

五、Chunk

1、定义

2、new和delete重载

3、chop和next_chop方法

六、ChunkPool

1、定义

2、allocate和free

3、initialize和clean

七、HandleMarkCleaner

1、定义

​ 2、构造和析构方法


上篇博客《Hotspot 方法调用之JavaCalls 源码解析》分析了本地代码调用Java方法的核心入口JavaCalls相关类的实现,本篇博客继续深入分析HandleMark相关类的实现。

一、HandleMark

1、定义

       在执行Java方法调用前会先构建一个JavaCallWrapper实例,然后再构造一个HandleMark实例。HandleMark的定义在hotspot/src/share/vm/runtime/handles.hpp中,主要用于记录当前线程的HandleArea的内存地址top,执行方法调用后,HandleMark实例自动销毁,在HandleMark的析构函数中会将HandleArea的当前内存地址到方法调用前的内存地址top之间的所有分配的oop都销毁掉,然后恢复当前线程的HandleArea的内存地址top到方法调用前的状态。HandleMark一般情况下直接在线程栈内存上分配,应该继承自StackObj,但是部分情况下HandleMark也需要在堆内存上分配,所以没有继承自StackObj,并且为了支持在堆内存上分配,重载了new和delete方法。

    HandleMark定义的属性都是私有属性,具体如下:

  • _thread:Thread *,表示拥有此HandleMark实例的Thread
  • _area:HandleArea *,此HandleMark实例保存的HandleArea
  • _chunk:Chunk*,保存HandleArea的Chunk
  • _hwm,_max:char *,保存的HandleArea的信息
  • _size_in_bytes:size_t,保存的HandleArea的大小
  • _previous_handle_mark:当前线程的上一个活跃的HandleMark实例

    除构造析构函数外,HandleMark定义的方法有三种:

  • 属性相关的,如set_previous_handle_mark,previous_handle_mark,size_in_bytes
  • HandleMarkCleaner调用的方法,push在HandleMarkCleaner构造时调用,pop_and_restore在HandleMarkCleaner销毁时调用
  • 重载的new和delete方法,支持从堆内存中分配。

2、构造和析构方法

      HandleMark的核心方法就是构造和析构方法,其源码说明如下:

HandleMark(Thread* thread)                      { initialize(thread); }

inline HandleMark::HandleMark() {
  initialize(Thread::current());
}

void HandleMark::initialize(Thread* thread) {
   //将当前线程的_area的属性保存到新的HandleMark实例中
  _thread = thread;
  // 保存当前线程的area
  _area  = thread->handle_area();
  // 保存当前线程的area的相关属性
  _chunk = _area->_chunk;
  _hwm   = _area->_hwm;
  _max   = _area->_max;
  _size_in_bytes = _area->_size_in_bytes;
  debug_only(_area->_handle_mark_nesting++);
  assert(_area->_handle_mark_nesting > 0, "must stack allocate HandleMarks");
  debug_only(Atomic::inc(&_nof_handlemarks);)

  //将当前HandleMark实例同线程关联起来
  set_previous_handle_mark(thread->last_handle_mark());
  thread->set_last_handle_mark(this);
}

HandleMark::~HandleMark() {
  HandleArea* area = _area;   // help compilers with poor alias analysis
  //检查当前线程的HandleArea是否改变
  assert(area == _thread->handle_area(), "sanity check");
  assert(area->_handle_mark_nesting > 0, "must stack allocate HandleMarks" );
  debug_only(area->_handle_mark_nesting--);


  //如果存在下一个Chunk
  if( _chunk->next() ) {
    // reset arena size before delete chunks. Otherwise, the total
    // arena size could exceed total chunk size
    //校验area当前的大小大于HandleMark在构造函数中保存的大小
    assert(area->size_in_bytes() > size_in_bytes(), "Sanity check");
    //恢复area的大小到HandleMark构造时的状态
    area->set_size_in_bytes(size_in_bytes());
    //删除当前Chunk以后的所有Chunk,即在方法调用期间新创建的Chunk
    _chunk->next_chop();
  } else {
    //如果没有下一个Chunk,说明未分配新的Chunk,则area的大小应该保持不变
    assert(area->size_in_bytes() == size_in_bytes(), "Sanity check");
  }
  //恢复area的属性到HandleMark构造时的状态
  area->_chunk = _chunk;
  area->_hwm = _hwm;
  area->_max = _max;


  //解除当前HandleMark跟线程的关联
  _thread->set_last_handle_mark(previous_handle_mark());
}

     参考下面HandleArea等的描述可知,创建一个新的HandleMark以后,新的HandleMark保存当前线程的area的当前chunk,_hwm ,_max等属性,执行方法期间新创建的Handle实例是在当前线程的area中分配内存,这会导致当前线程的area的当前chunk,_hwm ,_max等属性发生变更,因此方法执行完成需要将这些属性恢复成方法调用前的状态,并把方法调用过程中新创建的Handle实例的内存给释放掉。

二、HandleArea

     HandleArea的定义同样位于hotspot/src/share/vm/runtime/handles.hpp中,表示一片专门用于分配Handle的内存区域,其继承关系如下图,后面逐一说明相关类。

   HandleArea只添加了一个私有属性HandleArea* _prev,表示HandleArea链中前一个HandleArea实例。

   HandleArea的公共方法只有三个,

  • allocate_handle:用于分配保存oop的内存
  • oops_do:垃圾回收时遍历对应引用
  • used:获取已经使用的内存大小

  其中 allocate_handle的源码说明如下:

public:
  oop* allocate_handle(oop obj) { return real_allocate_handle(obj); }

//oopSize就是指针的大小
const int oopSize            = sizeof(char*);

 private:
  oop* real_allocate_handle(oop obj) {
    oop* handle = (oop*) Amalloc_4(oopSize);
    //将handle指向的内存赋值成obj
    *handle = obj;
    return handle;
  }

其调用方如下图:

 比如其中Handle(oop)的实现如下:

  参考

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值