我目前正在进行一次奇怪的旅行,我正在尝试创建一个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
字段的地址。
带来你的知识真棒人!谢谢! :)
答案 0 :(得分:3)
你通常不能这样做。
Dalvik曾经通过JNI传递对象地址,但在ICS版本中切换到间接引用。这样做的动机是使堆栈中的对象更容易移动,例如用于压实垃圾收集器。如果应用程序代码可以获取JNI可见的任何对象的地址,那么GC将无法移动这些对象,因为本机代码可能在GC运行时访问它们。 (从Android 4.4 KitKat开始,对象没有移动,但我认为在即将发布的版本中会有所改变。)
我认为Android的大多数版本都会从System#identityHashCode()
返回对象地址,从而无需使用JNI,但如果现在有效,我预计它也会很快崩溃。
当然,如果您确实设法获取地址,它只会告诉您地址是,而不是地址是,因为VM是随时可以自由重新定位对象。