使用NDK获取Object的指向内存地址

时间:2014-10-25 03:18:45

标签: java android android-ndk java-native-interface dalvik

我目前正在进行一次奇怪的旅行,我正在尝试创建一个native方法,该方法返回Java Object的内存地址。

我已正确配置Android的NDK,我的Java方法是:

public static native String getAddressOf(Object obj);

之后,我在C中的原生实现:

jstring Java_com_danysantiago_andmemutil_MemoryUtils_getAddressOf(JNIEnv *env, jobject clazz, jobject obj) {
    char buffer[11];
    sprintf(buffer, "%p", obj);
    return (*env)->NewStringUTF(env, buffer);
}

但由于某些原因,无论我在模拟器上使用多少应用程序,返回的字符串地址总是相同的。我假设我没有得到实际的内存指针或者我对Java如何存储在内存中的Java知识是错误的。

更多背景故事: 我已经在this stackoverflow answer之后的计算机JVM上运行的标准Java应用程序中成功获取了Object的地址。我能够确认它,因为我进行了堆转储然后使用MAT来搜索导致我的虚拟类的实例的地址。但是,Android中无法使用sun.misc.unsafe

当我尝试遵循类似的步骤,进行Android应用程序的堆转储并搜索该方法返回的地址时,我得不到结果,但是如果我使用OQL,则可以使用MAT我可以找到具有不同地址的虚拟类的实例。

看看如何使用unsafe获取地址让我想知道实际上我也是如此,使用本机代码,必须计算检查Object字段的地址。

带来你的知识真棒人!谢谢! :)

1 个答案:

答案 0 :(得分:3)

你通常不能这样做。

Dalvik曾经通过JNI传递对象地址,但在ICS版本中切换到间接引用。这样做的动机是使堆栈中的对象更容易移动,例如用于压实垃圾收集器。如果应用程序代码可以获取JNI可见的任何对象的地址,那么GC将无法移动这些对象,因为本机代码可能在GC运行时访问它们。 (从Android 4.4 KitKat开始,对象没有移动,但我认为在即将发布的版本中会有所改变。)

我认为Android的大多数版本都会从System#identityHashCode()返回对象地址,从而无需使用JNI,但如果现在有效,我预计它也会很快崩溃。

当然,如果您确实设法获取地址,它只会告诉您地址,而不是地址,因为VM是随时可以自由重新定位对象。