Hotspot JNI引用管理源码解析

目录

一、JNI引用操作API

二、Handle

三、Metadata Handles

四、KlassHandle

五、JNIHandles

1、本地引用操作

2、全局引用操作

3、全局弱引用

4、引用类型判断

  5、引用遍历

六、JNIHandleBlock

1、定义

2、allocate_block和release_block

3、allocate_handle和rebuild_free_list

七、结论


     在Hotspot JNIEnv API详解(一)中我们讲到了JNI中有四种引用类型,JNIInvalidRefType无效引用,JNILocalRefType本地引用,JNIGlobalRefType全局引用,JNIWeakGlobalRefType全局弱引用,本地引用类似于方法调用中局部变量对应的对象引用,全局引用类似于类静态变量对应的对象引用,全局弱引用对应Java中的PhantomReferences虚引用。Java代码的解释执行过程中并没有所谓的引用类型,为啥本地代码需要引入引用类型了?Java代码中引用或本地代码中的引用究竟有啥区别?本地引用在本地方法结束后自动销毁,全局引用必须手动调用DeleteGlobalRef方法才能释放对象引用,这是怎么实现的?

一、JNI引用操作API

       JNI引用操作的API的用法和示例在Hotspot JNIEnv API详解(一)都有说明,这里重点关注其源码实现,具体实现在hotspot/src/share/vm/prims/jni.cpp中,核心代码说明如下:

JNI_ENTRY(jobject, jni_NewGlobalRef(JNIEnv *env, jobject ref))

  //resolve方法是从ref解析出oop
  Handle ref_handle(thread, JNIHandles::resolve(ref));
  //创建全局引用
  jobject ret = JNIHandles::make_global(ref_handle);

  return ret;
JNI_END

JNI_ENTRY_NO_PRESERVE(void, jni_DeleteGlobalRef(JNIEnv *env, jobject ref))
  //删除全局引用
  JNIHandles::destroy_global(ref);

JNI_END

JNI_ENTRY(jobject, jni_NewLocalRef(JNIEnv *env, jobject ref))

  //创建本地引用,resolve方法同上
  jobject ret = JNIHandles::make_local(env, JNIHandles::resolve(ref));

  return ret;
JNI_END

JNI_QUICK_ENTRY(void, jni_DeleteLocalRef(JNIEnv *env, jobject obj))

  //删除本地引用
  JNIHandles::destroy_local(obj);

JNI_END

JNI_ENTRY(jweak, jni_NewWeakGlobalRef(JNIEnv *env, jobject ref))
 
  //同上,创建全局弱引用
  Handle ref_handle(thread, JNIHandles::resolve(ref));
  jweak ret = JNIHandles::make_weak_global(ref_handle);

  return ret;
JNI_END

JNI_ENTRY(void, jni_DeleteWeakGlobalRef(JNIEnv *env, jweak ref))
  //删除全局弱引用
  JNIHandles::destroy_weak_global(ref);

JNI_END

JNI_LEAF(jobjectRefType, jni_GetObjectRefType(JNIEnv *env, jobject obj))

  //条件判断不同的引用类型
  jobjectRefType ret;
  if (JNIHandles::is_local_handle(thread, obj) ||
      JNIHandles::is_frame_handle(thread, obj))
    ret = JNILocalRefType;
  else if (JNIHandles::is_global_handle(obj))
    ret = JNIGlobalRefType;
  else if (JNIHandles::is_weak_global_handle(obj))
    ret = JNIWeakGlobalRefType;
  else
    ret = JNIInvalidRefType;

  return ret;
JNI_END

JNI_ENTRY(jint, jni_PushLocalFrame(JNIEnv *env, jint capacity))
 
 //只是校验下参数是否合法
  if (capacity < 0 ||
      ((MaxJNILocalCapacity > 0) && (capacity > MaxJNILocalCapacity))) {
    return JNI_ERR;
  }
  //原来的active_handles
  JNIHandleBlock* old_handles = thread->active_handles();
  //创建新的JNIHandleBlock
  JNIHandleBlock* new_handles = JNIHandleBlock::allocate_block(thread);
  assert(new_handles != NULL, "should not be NULL");
  //将原来的active_handles设置为的新的JNIHandleBlock的pop_frame_link,即通过pop_frame_link可以不断往上
  //追溯至最开始的active_handles
  new_handles->set_pop_frame_link(old_handles);
  //将新创建的JNIHandleBlock设置为active_handles
  thread->set_active_handles(new_handles);
  jint ret = JNI_OK;

  return ret;
JNI_END


JNI_ENTRY(jobject, jni_PopLocalFrame(JNIEnv *env, jobject result))
  
  Handle result_handle(thread, JNIHandles::resolve(result));
  
  JNIHandleBlock* old_handles = thread->active_handles();
  //当前JNIHandleBlock上一个的JNIHandleBlock
  JNIHandleBlock* new_handles = old_handles->pop_frame_link();
  if (new_handles != NULL) {
     //active_handles恢复至原来的JNIHandleBlock
    thread->set_active_handles(new_handles);
    //old_handles释放
    old_handles->set_pop_frame_link(NULL);              // clear link we won't release new_handles below
    JNIHandleBlock::release_block(old_handles, thread); // may block
    result = JNIHandles::make_local(thread, result_handle());
  }

  return result;
JNI_END

  从上述源码可知,JNI引用操作实际使用JNIHandles实现的。

二、Handle

      Handle相当于一个值对象(ValueObj,即目标值的一个包装类),本身可以作为参数或者返回值,通过操作符重载可以像直接使用值使用Handle。该对象主要是在垃圾回收期间保护用来保护oop,即通过Handle实现垃圾回收期间对象复制导致oop发生改变但oop使用方无感知,因此JVM要求oop无论是作为参数还是返回值必须使用Handle来传递。其定义在hotspot/src/share/vm/runtime/handles.hpp中,实现在同目录下的handles.cpp中,具体定义如下:

class Handle VALUE_OBJ_CLASS_SPEC {
 private:
 //目标值,注意oop本身实际是oopDesc*的别名,即此处是oopDesc实例的指针的指针
  oop* _handle;

 protected:
  //这两个方法都是返回oop,non_null_obj做了非空校验
  oop     obj() const                            { return _handle == NULL ? (oop)NULL : *_handle; }
  oop     non_null_obj() const                   { assert(_handle != NULL, "resolving NULL handle"); return *_handle; }

 public:
  //构建空对象
  Handle()                                       { _handle = NULL; }
  //底层实现会获取当前线程
  Handle(oop obj);
  //底层实现会校验thread是否是当前线程
  Handle(Thread* thread, oop obj);

  //操作符重载
  oop     operator () () const                   { return obj(); }
  oop     operator -> () const                   { return non_null_obj(); }
  bool    operator == (oop o) const              { return obj() == o; }
  bool    operator == (const Handle& h) const          { return obj() == h.obj(); }

  //非空
  bool    is_null() const                        { return _handle == NULL; }
  bool    not_null() const                       { return _handle != NULL; }

  // Debugging
  void    print()                                { obj()->print(); }
  
  //_handle不用从当前线程分配内存,直接赋值成目标值,这个方法很少使用
  //dummy是无效参数,避免同Handle(oop obj)混淆
  Handle(oop *handle, bool dummy)                { _handle = handle; }
  
  //直接访问_handle,因为C是值复制,所以这种方式无法保证原来的值是有效的,使用不安全
  oop* raw_value()                               { return _handle; }
  //获取原始的oop
  static oop raw_resolve(oop *handle)            { return handle == NULL ? (oop)NULL : *handle; }
};

不同oop对应的Handle不同,Handle是所有类型的Handle的父类,其他子类都是通过宏定义实现的,如下图:

即Handle的子类包括instanceHandle,arrayHandle,objArrayHandle,typeArrayHandle,子类的构造方法跟Handle一致,只是加了一步oop类型校验。

     Handle的实现在hotspot/src/share/vm/runtime/handles.inline.hpp中,相关源码说明如下:

inline Handle::Handle(oop obj) {
  if (obj == NULL) {
    _handle = NULL;
  } else {
     //handle_area()方法返回当前线程的_handle_area属性,该属性是HandleArea实例指针
     //然后通过HandleArea 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值