Ying_526_ 2023-12-07 09:15 采纳率: 0%
浏览 37
已结题

获取java对象内存地址(Object hashCode)

jni如何获取hotspot中的oop结构体

Java jni 中:
环境:Mac M1 arm64 jdk17
问题描述:

传递Java 对象obj到native C++层时,C++收到的参数是obj
但是我两次分别传递不同对象时,发现obj的值和其地址都是相同的
我向其传递null空指针,obj也为NULL
按理说,obj是我传递的对象的引用,应该会随着我传递不同对象而发生改变,但是现在没有,请问这是为什么?

希望:传入不同对象返回不同对象的地址

本地方法:

    public static native long getAddress(Object obj);

C++代码

#include "address_NativeLibrary.h"
#include <iostream>

JNIEXPORT jlong JNICALL Java_address_NativeLibrary_getAddress
  (JNIEnv * env, jclass jclazz, jobject obj){

  if(obj== NULL) {
    std::cout << "obj 为空!!" << obj << std::endl;
    return -1;
  }
       std::cout << "  "<<  obj << "  ";
       std::cout << "  "<<  &obj << "  ";
       long ret = (long)(&obj);
       return ret;
  }

调用代码

package address;

public class Main {

    public static void main(String[] args) {
        Integer a = 21;
        Integer b = 21;
        NativeLibrary.getAddress(a);
        NativeLibrary.getAddress(b);
    }

}

运行结果:(没有换行,我换个行,更直观)

 0x16b962b08    0x16b962a50  
 0x16b962b08    0x16b962a50  

我看到Object 类 hashCode native的源码中是可以获取到地址的

static inline intptr_t get_next_hash(Thread* current, oop obj) {
  intptr_t value = 0;
  if (hashCode == 0) {
    // This form uses global Park-Miller RNG.
    // On MP system we'll have lots of RW access to a global, so the
    // mechanism induces lots of coherency traffic.
    value = os::random();
  } else if (hashCode == 1) {
    // This variation has the property of being stable (idempotent)
    // between STW operations.  This can be useful in some of the 1-0
    // synchronization schemes.
    intptr_t addr_bits = cast_from_oop<intptr_t>(obj) >> 3;
    value = addr_bits ^ (addr_bits >> 5) ^ GVars.stw_random;
  } else if (hashCode == 2) {
    value = 1;            // for sensitivity testing
  } else if (hashCode == 3) {
    value = ++GVars.hc_sequence;
  } else if (hashCode == 4) {
    value = cast_from_oop<intptr_t>(obj);
  } else {
    // Marsaglia's xor-shift scheme with thread-specific state
    // This is probably the best overall implementation -- we'll
    // likely make this the default in future releases.
    unsigned t = current->_hashStateX;
    t ^= (t << 11);
    current->_hashStateX = current->_hashStateY;
    current->_hashStateY = current->_hashStateZ;
    current->_hashStateZ = current->_hashStateW;
    unsigned v = current->_hashStateW;
    v = (v ^ (v >> 19)) ^ (t ^ (t >> 8));
    current->_hashStateW = v;
    value = v;
  }

  value &= markWord::hash_mask;
  if (value == 0) value = 0xBAD;
  assert(value != markWord::no_hash, "invariant");
  return value;
}

这里当hashCode为4时返回的就是Java对象的地址,我通过jdk中的jhsdb工具验证了
但是oop结构体好像拿不到

Objec hashCode源码参考连接:https://www.yuque.com/yuqueyonghu1o4dun/uh2m8v/iwgwirqq7zrfvx2w?singleDoc# 《JNI (Java Native Interface)》

  • 写回答

14条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2023-12-07 09:15
    关注

    引自强大而免费的微信小程序:皆我百晓生

    在JNI中,对象引用是一个特殊的类型 jobject,在C++层面上,它实际上是一个指向 jobject 的指针。因此,当你输出 obj 的地址时,实际上是输出了 jobject 的指针的地址,而不是对象本身的地址。

    此外,你传递的 obj 参数在JNI层是一个副本,它指向Java中的对象。因此,即使你多次调用 NativeLibrary.getAddress() 并传递不同的Java对象,C++层接收的 obj 参数的指针地址也是相同的,因为它们都是指向Java对象的指针副本。

    如果你想在C++层获取Java对象的真实地址,而不是JNI层的指针副本,可以使用 GetObjectRefType() 方法来获取真实的Java对象的 jobject 地址。具体示例如下:

    #include "address_NativeLibrary.h"
    #include <iostream>
     
    JNIEXPORT jlong JNICALL Java_address_NativeLibrary_getAddress
      (JNIEnv * env, jclass jclazz, jobject obj) {
     
      if (obj == NULL) {
        std::cout << "obj 为空!!" << obj << std::endl;
        return -1;
      }
    
      jclass clazz = env->GetObjectClass(obj);
      jobjectRefType objType = env->GetObjectRefType(obj);
    
      if (objType == JNI_INVALID_REF_TYPE || objType == JNI_NULL) {
        std::cout << "无效的对象类型!!" << std::endl;
        return -1;
      }
    
      std::cout << "真实的对象地址: " << obj << std::endl;
      std::cout << "真实的对象类型: " << (objType == JNI_GLOBAL ? "全局引用" : "局部引用") << std::endl;
    
      jlong ret = reinterpret_cast<jlong>(obj);
      return ret;
    }
    

    这样,你就可以在C++层中获取到真实的Java对象的地址了。请注意,这个地址是本地地址,只在C++层有效,不能在Java层直接使用。

    希望可以帮助到你!

    评论 编辑记录

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 12月8日
  • 修改了问题 12月7日
  • 修改了问题 12月7日
  • 修改了问题 12月7日
  • 展开全部

悬赏问题

  • ¥15 微信小程序 前端页面内容搜索
  • ¥15 cpu是如何判断当前指令已经执行完毕,然后去执行下条指令的
  • ¥15 C++Codeinject远线程注入
  • ¥15 安装visual studio2022时visualstudiosetup启动不了,闪退。问题代号0x0和0x1389
  • ¥30 java spring boot2.5.3版本websocket连不上
  • ¥15 angular js调外部链接查看pdf
  • ¥15 openFOAM DPMFoam
  • ¥15 将查询到的值,赋值到table指定行中
  • ¥50 docker容器内部启动shell脚本多命令
  • ¥15 请问python的selenium怎么设置referer