Java Android (ART) 崩溃并出现错误 JNI DETECTED ERROR IN APPLICATION: jarray is an invalid stack间接引用表或无效引用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/29879220/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android (ART) crash with error JNI DETECTED ERROR IN APPLICATION: jarray is an invalid stack indirect reference table or invalid reference
提问by Stef
I am writing an Android application that processes a picture from the native C (NDK r10d). The code was working well until recent ART introduction that is more strict with JNI. So the code is working fine with Dalvik (e.g. on pre-Lolipop devices) but ii creates a SIGENV on the newest phones.
I now get the error:
我正在编写一个处理来自本机 C (NDK r10d) 的图片的 Android 应用程序。该代码运行良好,直到最近对 JNI 更加严格的 ART 引入。所以代码在 Dalvik 上运行良好(例如在 Lolipop 之前的设备上),但是 ii 在最新的手机上创建了一个 SIGENV。
我现在得到错误:
04-26 16:18:34.169: E/art(21443): 0xb4a2dd00 SpaceTypeMallocSpace begin=0x12c00000,end=0x12e01000,limit=0x32c00000,size=2MB,capacity=192MB,non_growth_limit_capacity=512MB,name="main rosalloc space"]
04-26 16:18:34.170: E/art(21443): 0xb4ae5640 allocspace main rosalloc space live-bitmap 3[begin=0x12c00000,end=0x32c00000]
04-26 16:18:34.170: E/art(21443): 0xb4ae5660 allocspace main rosalloc space mark-bitmap 3[begin=0x12c00000,end=0x32c00000]
04-26 16:18:34.170: E/art(21443): 0xb4874120 SpaceTypeImageSpace begin=0x6f5ab000,end=0x6ff21e58,size=9MB,name="/data/dalvik-cache/arm/system@[email protected]"]
04-26 16:18:34.170: E/art(21443): 0xb4875220 imagespace /data/dalvik-cache/arm/system@[email protected] live-bitmap 0[begin=0x6f5ab000,end=0x6ff21f00]
04-26 16:18:34.170: E/art(21443): 0xb4875220 imagespace /data/dalvik-cache/arm/system@[email protected] live-bitmap 0[begin=0x6f5ab000,end=0x6ff21f00]
04-26 16:18:34.170: E/art(21443): 0xb49d9dd0 SpaceTypeZygoteSpace begin=0x72f09000,end=0x740c7000,size=17MB,name="Zygote space"]
04-26 16:18:34.170: E/art(21443): 0xb4875440 allocspace zygote / non moving space live-bitmap 0[begin=0x72f09000,end=0x740c7000]
04-26 16:18:34.170: E/art(21443): 0xb4875460 allocspace zygote / non moving space mark-bitmap 0[begin=0x72f09000,end=0x740c7000]
04-26 16:18:34.170: E/art(21443): 0xb4a2dc80 SpaceTypeMallocSpace begin=0x740c7000,end=0x740d6000,limit=0x76f09000,size=60KB,capacity=46MB,non_growth_limit_capacity=46MB,name="non moving space"]
04-26 16:18:34.170: E/art(21443): 0xb4ae5460 allocspace non moving space live-bitmap 4[begin=0x740c7000,end=0x76f09000]
04-26 16:18:34.170: E/art(21443): 0xb4ae53c0 allocspace non moving space mark-bitmap 4[begin=0x740c7000,end=0x76f09000]
04-26 16:18:34.170: E/art(21443): 0xb486d340 large object space:GcRetentionPolicyAlwaysCollect
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: jarray is an invalid stack indirect reference table or invalid reference: 0x740c9268 (0xdead4321)
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] in call to GetByteArrayElements
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] from boolean com.googlecode.leptonica.android.Pix.nativeGetData(int, byte[])
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] "main" prio=5 tid=1 Runnable
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] | group="main" sCount=0 dsCount=0 obj=0x72f09000 self=0xb4827800
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] | sysTid=21443 nice=0 cgrp=default sched=0/0 handle=0xb6f6abec
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] | state=R schedstat=( 427402282 63106827 397 ) utm=28 stm=14 core=3 HZ=100
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] | stack=0xbe5e3000-0xbe5e5000 stackSize=8MB
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] | held mutexes= "mutator lock"(shared held)
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #00 pc 00004e64 /system/lib/libbacktrace_libc++.so (UnwindCurrent::Unwind(unsigned int, ucontext*)+23)
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #01 pc 00003665 /system/lib/libbacktrace_libc++.so (Backtrace::Unwind(unsigned int, ucontext*)+8)
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #02 pc 00256429 /system/lib/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, char const*, art::mirror::ArtMethod*)+84)
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #03 pc 00238fe7 /system/lib/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const+158)
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #04 pc 000b191b /system/lib/libart.so (art::JniAbort(char const*, char const*)+610)
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #05 pc 000b2055 /system/lib/libart.so (art::JniAbortF(char const*, char const*, ...)+68)
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #06 pc 000b4455 /system/lib/libart.so (art::ScopedCheck::Check(bool, char const*, ...) (.constprop.129)+480)
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #07 pc 000bee03 /system/lib/libart.so (art::CheckJNI::GetByteArrayElements(_JNIEnv*, _jbyteArray*, unsigned char*)+62)
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #08 pc 00239478 /data/app/com.bill2bin.core.lib.demo-1/lib/arm/liblept.so (_JNIEnv::GetByteArrayElements(_jbyteArray*, unsigned char*)+48)
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #09 pc 0023992c /data/app/com.bill2bin.core.lib.demo-1/lib/arm/liblept.so (Java_com_googlecode_leptonica_android_Pix_nativeGetData+540)
04-26 16:18:34.263: A/art(21443): art/runtime/check_jni.cc:65] native: #10 pc 0008d3b5 /data/dalvik-cache/arm/data@[email protected]@[email protected] (Java_com_googlecode_leptonica_android_Pix_nativeGetData__I_3B+104)
04-26 16:18:34.264: A/art(21443): art/runtime/check_jni.cc:65] at com.googlecode.leptonica.android.Pix.nativeGetData(Native method)
04-26 16:18:34.264: A/art(21443): art/runtime/check_jni.cc:65] at com.googlecode.leptonica.android.Pix.getData(Pix.java:94)
04-26 16:18:34.264: A/art(21443): art/runtime/check_jni.cc:65] at com.bill2bin.core.lib.demo.VideoPipeDebug.testDoJNIDebug(VideoPipeDebug.java:449)
04-26 16:18:34.264: A/art(21443): art/runtime/check_jni.cc:65] at com.bill2bin.core.lib.demo.CameraActivity.runTest1(CameraActivity.java:133)
The code I run in Java is:
我在Java中运行的代码是:
/**
* Return the raw bytes of the native PIX object. You can reconstruct the
* Pix from this data using createFromPix().
*
* @return a copy of this PIX object's raw data
*/
public byte[] getData() {
int size = nativeGetDataSize(mNativePix);
// Size is usually quite big since I work on pictures (1Mo-300Ko)
byte[] buffer = new byte[size];
if (!nativeGetData(mNativePix, buffer)) {
throw new RuntimeException("native getData failed");
}
return buffer;
}
private static native boolean nativeGetData(long nativePix, byte[] data);
The corresponding native code is:
对应的原生代码是:
jboolean Java_com_googlecode_leptonica_android_Pix_nativeGetData(JNIEnv *env,
jclass clazz, jlong nativePix, jbyteArray data) {
PIX *pix = (PIX *) nativePix;
jbyte *data_buffer = env->GetByteArrayElements(data, NULL);
l_uint8 *byte_buffer = (l_uint8 *) data_buffer;
size_t size = 4 * pixGetWpl(pix) * pixGetHeight(pix);
memcpy(byte_buffer, pixGetData(pix), size);
env->ReleaseByteArrayElements(data, data_buffer, 0);
return JNI_TRUE;
}
It seems that GetByteArrayElements is the source of the error, but the JNIEnv reference and the jbyteArray are provided by Android and I do not store nor modify them. Since the buffer array is always allocated in the same Java thread, I do not see how it can be corrupted...I am quite puzzled :)
What can be the source of this issue?
Is the heap too small? Or is it an ART issue (I really doubt it though...) ?
Thanks for you help !
似乎 GetByteArrayElements 是错误的来源,但 JNIEnv 引用和 jbyteArray 由 Android 提供,我不存储也不修改它们。由于缓冲区数组总是在同一个 Java 线程中分配,我看不出它是如何被破坏的......我很困惑:)
这个问题的根源是什么?
堆太小了吗?或者它是一个 ART 问题(虽然我真的很怀疑......)?
谢谢你的帮助!
采纳答案by Stef
Following Alex Cohn 's advice I made the following code work:
JAVA
按照 Alex Cohn 的建议,我做了以下代码工作:
JAVA
public byte[] getData() {
byte[] buffer = nativeGetData(mNativePix);
if (buffer == null) {
throw new RuntimeException("native getData failed");
}
return buffer;
}
private static native byte[] nativeGetData(long nativePix);
Native
本国的
jbyteArray Java_com_googlecode_leptonica_android_Pix_nativeGetData(
JNIEnv *env, jclass clazz, jlong nativePix) {
PIX *pix = (PIX *) nativePix;
// Get the size
size_t size = 4 * pixGetWpl(pix) * pixGetHeight(pix);
jbyteArray result = env->NewByteArray(size);
if (result == NULL) {
LOGE("Cannot allocate JNI Byte Array");
return NULL; /* out of memory error thrown */
}
// move from the Pix to the java structure
env->SetByteArrayRegion(result, 0, size,(jbyte*)pixGetData(pix));
return result;
}
Thanks!
谢谢!
回答by Evan Lin
This means that it's valid for the duration of the current native method in the current thread. Even if the object itself continues to live on after the native method returns, the reference is not valid.
这意味着它在当前线程中的当前本地方法的持续时间内有效。即使对象本身在本机方法返回后继续存在,引用也是无效的。
Try replace this in your jclass/jarray declare.
尝试在您的 jclass/jarray 声明中替换它。
jclass localClass = env->FindClass("MyClass");
jclass globalClass = reinterpret_cast<jclass>(env->NewGlobalRef(localClass));
Refer JNI Tips
参考JNI 技巧
回答by Alex
I faced the same problem. I've written a C function, taking jbyteArray from Java, which was very similar to other already existing and working functions. But it crashed violently with horrible messages about accessing deleted long time ago object, accessing record number ~6000 in a table with fifty records etc... I simplified my code to the minimum and noticed that function fails during any attempt to access jbyteArray which has been passed to it. No matter from which thread I made call, no matter how I formed this array. I checked signature and all that I could. Function definitely had been called because I could print to log from it.
我遇到了同样的问题。我已经编写了一个 C 函数,它从 Java 中获取 jbyteArray,它与其他已经存在和工作的函数非常相似。但它猛烈地崩溃了关于访问已删除很久以前对象的可怕消息,在有五十条记录的表中访问记录号 ~6000 等等......我将我的代码简化到最低限度,并注意到该函数在任何尝试访问 jbyteArray 时都失败了,它有被传递给它。无论我从哪个线程调用,无论我如何形成这个数组。我检查了签名和所有我能做的。函数肯定已被调用,因为我可以打印以从中记录。
After I've read this topic I felt doomed :) I definitely couldn't generate data inside of my c-function.
在我读完这个主题后,我觉得我注定要失败:) 我绝对无法在我的 c 函数中生成数据。
What helped to me: I have rewritten this function by hand (no copy-paste) in slightly different part of the source file. I also changed its name just in case. Old function's body was deleted. And it immediately began to work properly.
对我有什么帮助:我在源文件的稍微不同的部分手动重写了这个函数(没有复制粘贴)。为了以防万一,我也更改了它的名字。旧函数的主体被删除。它立即开始正常工作。
I don't know what it was, but I faced similar situations in my life a few times in pure C and Perl languages.
我不知道那是什么,但我在生活中用纯 C 和 Perl 语言遇到过几次类似的情况。
Android Studio. AOSP 7.1.2 fork.
安卓工作室。AOSP 7.1.2 前叉。