JNI Local Reference Changes in ICS
来源:互联网 发布:mysql数据导出excel 编辑:程序博客网 时间:2024/04/29 03:05
http://androidhtc.org/jni-local-reference-changes-in-ics/
[This post is by Elliott Hughes, a Software package Engineer on the Dalvik staff. &mdash Tim Bray]
If you don’t publish native code that utilizes JNI, you can end reading through now. If you do publish native code that employs JNI, you truly need to have to read this.
What’s modifying, and why?
Each and every developer wants a great rubbish collector. The very best garbage collectors transfer objects about. This allows them offer really low-cost allocation and bulk deallocation, avoids heap fragmentation, and could increase locality. Heading objects about is a difficulty if you’ve handed out pointers to them to native code. JNI utilizes kinds this sort of as jobject
to resolve this problem: rather than handing out direct pointers, you’re provided an opaque take care of that can be traded in for a pointer when essential. By making use of handles, when the rubbish collector moves an object, it just has to update the handle table to point to the object’s new place. This implies that native code won’t be left holding dangling pointers every time the garbage collector runs.
In previous releases of Android, we did not use indirect handles we utilised direct pointers. This did not seem to be like a dilemma as prolonged as we didn’t have a rubbish collector that moves objects, but it permit you compose buggy code that nevertheless seemed to perform. In Ice Cream Sandwich, even though we have not yet applied these a garbage collector, we have moved to indirect references so you can start detecting bugs in your native code.
Ice Cream Sandwich attributes a JNI bug compatibility mode so that as prolonged as your AndroidManifest.xml’s targetSdkVersion is less than Ice Cream Sandwich, your code is exempt. But as soon as you update your targetSdkVersion, your code demands to be appropriate.
CheckJNI has been updated to detect and report these problems, and in Ice Cream Sandwich, CheckJNI is on by default if debuggable="correct"
in your manifest.
A quick primer on JNI references
In JNI, there are numerous sorts of reference. The two most important kinds are regional references and global references. Any provided jobject
can be either local or world-wide. (There are weak globals as well, but they have a separate sort, jweak
, and aren’t exciting here.)
The international/local distinction has an effect on each life time and scope. A worldwide is usable from any thread, using that thread’s JNIEnv*
, and is legitimate till an explicit get in touch with toDeleteGlobalRef()
. A local is only usable from the thread it was initially handed to, and is valid until finally possibly an explicit phone to DeleteLocalRef()
or, much more commonly, until you return from your native technique. When a native technique returns, all neighborhood references are automatically deleted.
In the outdated technique, where neighborhood references have been direct pointers, nearby references had been by no means genuinely invalidated. That meant you could use a local reference indefinitely, even if you’d explicitly named DeleteLocalRef()
on it, or implicitly deleted it withPopLocalFrame()
!
Though any given JNIEnv*
is only valid for use on 1 thread, simply because Android by no means had any per-thread state in a JNIEnv*
, it used to be possible to get absent with making use of a JNIEnv*
on the improper thread. Now there is a per-thread regional reference table, it’s important that you only use a JNIEnv*
on the appropriate thread.
These are the bugs that ICS will detect. I’ll go through a couple of typical situations to illustrate these issues, how to spot them, and how to resolve them. It’s critical that you do fix them, since it’s likely that potential Android releases will employ relocating collectors. It will not be feasible to provide a bug-compatibility mode indefinitely.
Common JNI reference bugs
Bug: Forgetting to phone NewGlobalRef()
when stashing a jobject
in a native peer
If you have a native peer (a lengthy-lived native object corresponding to a Java object, normally created when the Java object is created and destroyed when the Java object’s finalizer runs), you should not stash a jobject
in that native object, because it will not be valid subsequent time you attempt to use it. (Equivalent is true of JNIEnv*
s. They may be valid if the following native phone occurs on the exact same thread, but they will not be valid in any other case.)
class MyPeer manifeste: MyPeer(jstring s) str_ = s // Error: stashing a reference with no guaranteeing it’s global. jstring str_ static jlong MyClass_newPeer(JNIEnv* env, jclass) jstring regional_ref = env->NewStringUTF("hi there, entire world!") MyPeer* peer = new MyPeer(regional_ref) return static_cast<jlong>(reinterpret_cast<uintptr_t>(peer)) // Error: local_ref is no more time valid when we return, but we've saved it in 'peer'. static void MyClass_printString(JNIEnv* env, jclass, jlong peerAddress) MyPeer* peer = reinterpret_cast<MyPeer*>(static_cast<uintptr_t>(peerAddress)) // Error: peer->str_ is invalid! ScopedUtfChars s(env, peer->str_) std::cout << s.do_str() << std::endl
The correct for this is to only keep JNI worldwide references. Simply because there is in no way any automatic cleanup of JNI worldwide references, it’s critically important that you clean them up oneself. This is created somewhat awkward by the fact that your destructor will not have a JNIEnv*
. The least complicated fix is usually to have an explicit ‘destroy‘ purpose for your native peer, named from the Java peer’s finalizer:
course MyPeer manifeste: MyPeer(JNIEnv* env, jstring s) this->s = env->NewGlobalRef(s) ~MyPeer() assert(s == NULL) void ruin(JNIEnv* env) env->DeleteGlobalRef(s) s = NULL jstring s
You ought to often have matching calls to NewGlobalRef()
/DeleteGlobalRef()
. CheckJNI will catch global reference leaks, but the restrict is quite large (2000 by default), so observe out.
If you do have this class of error in your code, the crash will appear something like this:
JNI ERROR (app bug): accessed stale nearby reference 0x5900021 (index eight in a table of size eight) JNI WARNING: jstring is an invalid neighborhood reference (0x5900021) in LMyClass.printString:(J)V (GetStringUTFChars) "principal" prio=5 tid=one RUNNABLE | group="major" sCount= dsCount= obj=0xf5e96410 self=0x8215888 | sysTid=11044 great= sched=/ cgrp=[n/a] deal with=-152574256 | schedstat=( 156038824 600810 47 ) utm=14 stm=2 core= at MyClass.printString(Native Approach) at MyClass.principal(MyClass.java:thirteen)
If you’re making use of yet another thread’s JNIEnv*
, the crash will appear a thing like this:
JNI WARNING: threadid=eight utilizing env from threadid=1 in LMyClass.printString:(J)V (GetStringUTFChars) "Thread-ten" prio=five tid=eight NATIVE | group="major" sCount= dsCount= obj=0xf5f77d60 self=0x9f8f248 | sysTid=22299 nice= sched=/ cgrp=[n/a] deal with=-256476304 | schedstat=( 153358572 709218 48 ) utm=12 stm=four core=eight at MyClass.printString(Native Technique) at MyClass$ 1.operate(MyClass.java:15)
Bug: Mistakenly assuming FindClass()
returns global references
FindClass()
returns local references. A lot of folks believe otherwise. In a technique with no course unloading (like Android), you can treat jfieldID and jmethodID as if they had been global. (They are not actually references, but in a system with course unloading there are equivalent life time concerns.) But jclass is a reference, and FindClass()
returns neighborhood references. A typical bug pattern is “static jclass”. Unless of course you’re manually turning your nearby references into international references, your code is broken. Here’s what appropriate code must seem like:
static jclass gMyClass static jclass gSomeClass static void MyClass_nativeInit(JNIEnv* env, jclass myClass) // ‘myClass’ (and any other non-primitive arguments) are only local references. gMyClass = env->NewGlobalRef(myClass) // FindClass only returns nearby references. jclass someClass = env->FindClass("SomeClass") if (someClass == NULL) return // FindClass already threw an exception this kind of as NoClassDefFoundError. gSomeClass = env->NewGlobalRef(someClass)
If you do have this class of error in your code, the crash will look a thing like this:
JNI ERROR (app bug): try to use stale nearby reference 0x4200001d (must be 0x4210001d) JNI WARNING: 0x4200001d is not a legitimate JNI reference in LMyClass.useStashedClass:()V (IsSameObject)
Bug: Calling DeleteLocalRef()
and continuing to use the deleted reference
It shouldn’t require to be explained that it is illegal to proceed to use a reference right after callingDeleteLocalRef()
on it, but since it utilized to operate, so you may possibly have produced this error and not recognized. The typical pattern appears to be wherever native code has a long-working loop, and builders consider to clean up each and every simple local reference as they go to steer clear of hitting the neighborhood reference limit, but they unintentionally also delete the reference they want to use as a return price!
The resolve is trivial: really do not phone DeleteLocalRef()
on a reference you’re heading to use (wherever “use” incorporates “return”).
Bug: Calling PopLocalFrame()
and continuing to use a popped reference
This is a more delicate variant of the preceding bug. The PushLocalFrame()
and PopLocalFrame()
calls permit you bulk-delete regional references. When you get in touch with PopLocalFrame()
, you pass in the 1 reference from the body that you’d like to retain (normally for use as a return worth), or NULL. In the prior, you’d get away with incorrect code like the following:
static jobjectArray MyClass_returnArray(JNIEnv* env, jclass) env->PushLocalFrame(256) jobjectArray array = env->NewObjectArray(128, gMyClass, NULL) for (int i = i < 128 ++i) env->SetObjectArrayElement(array, i, newMyClass(i)) env->PopLocalFrame(NULL) // Error: should pass 'array'. return array // Error: array is no extended legitimate.
The correct is generally to pass the reference to PopLocalFrame()
. Notice in the over example that you do not need to preserve references to the personal array elements as extended as the GC understands about the array alone, it’ll just take treatment of the aspects (and any objects they point to in flip) itself.
If you do have this course of error in your code, the crash will appear some thing like this:
JNI ERROR (app bug): accessed stale nearby reference 0x2d00025 (index 9 in a table of size JNI WARNING: invalid reference returned from native code in LMyClass.returnArray:()[Ljava/lang/Object
Wrapping up
Sure, we asking for a little bit much more interest to detail in your JNI coding, which is additional function. But we feel that you will come out forward on the deal as we roll in much better and far more refined memory administration code.
- Android:JNI Local Reference Changes in ICS
- Android:JNI Local Reference Changes in ICS
- JNI Local Reference Changes in ICS
- JNI Local Reference Changes in ICS
- JNI Local Reference Changes in ICS
- JNI ERROR (app bug): attempt to use stale local reference 0x31900019(Android ICS(4.0+) JNI局部应用的变化)
- JNI ERROR (app bug): attempt to use stale local reference 0x31900019(Android ICS(4.0+) JNI局部应用的变化)
- 调用CallStaticObjectMethod报出JNI DETECTED ERROR IN APPLICATION: jclass is an invalid local reference:
- Unity Android 5.0上 JNI DETECTED ERROR IN APPLICATION: jclass is an invalid local reference
- JNI 的 local reference table overflowed 问题
- JNI--JNI ERROR (app bug): accessed stale local reference
- JNI ERROR (app bug): accessed stale local reference 0xbc00021 (index 8 in a table of size 8)
- JNI官方规范中文版——如何使用JNI中的global reference和local reference
- JNI官方规范中文版——如何使用JNI中的global reference和local reference
- JNI官方规范中文版——如何使用JNI中的global reference和local reference
- JNI官方规范中文版——如何使用JNI中的global reference和local reference
- JNI官方规范中文版——如何使用JNI中的global reference和local reference
- JNI官方规范中文版——如何使用JNI中的global reference和local reference
- Write Once, Run Anywhere:这不是Java,这是C#
- CSS3的盒模型 之高度一致 待查
- 20120822-[转]单片机实现软件复位(软复位)的方法及讨论
- SVN使用补遗-使用中应注意的问题
- gedit插件安装-classbrowser
- JNI Local Reference Changes in ICS
- gluBuild2DMipmaps()与glTexImage2D()的使用方法及区别
- Oracle 10G install for Redhat 6.2 x86
- 二进制“<<”: 没有找到接受“std::string”类型的右操作数的运算符(或没有可接受
- 从U盘安装 Ubuntu 10.04 64位服务器版
- 基于MINA构建简单高性能的NIO应用
- 往android的内核添加驱动(其实就是添加linux内核驱动)
- ssh连接linux慢处理方法
- 入职半年总结