JNI编程答疑

原文 https://developer.android.com/training/articles/perf-jni?hl=zh-cn#java

1 JaveVM 和JNIEnv是什么

jni相关的方法几乎都放在JNIEnv里面,JNIEnv是用于线程本地存储的,因此不能跨线程共享使用。如果一个类需要JNIEnv对象,不要直接传递JNIEnv,而应该通过JaveVM,通过GetEnv方法获得。

JNI defines two key data structures, "JavaVM" and "JNIEnv". Both of these are essentially pointers to pointers to function tables. (In the C++ version, they're classes with a pointer to a function table and a member function for each JNI function that indirects through the table.) The JavaVM provides the "invocation interface" functions, which allow you to create and destroy a JavaVM. In theory you can have multiple JavaVMs per process, but Android only allows one.

The JNIEnv provides most of the JNI functions. Your native functions all receive a JNIEnv as the first argument.

The JNIEnv is used for thread-local storage. For this reason, you cannot share a JNIEnv between threads. If a piece of code has no other way to get its JNIEnv, you should share the JavaVM, and use GetEnv to discover the thread's JNIEnv. (Assuming it has one; see AttachCurrentThread below.)

The C declarations of JNIEnv and JavaVM are different from the C++ declarations. The "jni.h" include file provides different typedefs depending on whether it's included into C or C++. For this reason it's a bad idea to include JNIEnv arguments in header files included by both languages. (Put another way: if your header file requires #ifdef __cplusplus, you may have to do some extra work if anything in that header refers to JNIEnv.)

2 线程和AttachCurrentThread 

android里面线程有两种,java层通过Thread.start方式启动的托管线程,是被JavaVM管理的。还有一种是native中通过pthread_create方法创建的线程,这种线程不受JavaVM管理,没有JNIEnv,因此不能做任何JNI调用,必须要AttachCurrentThread,这个方法会导致一个java.lang.Thread对象被构建,并且扔到“main” ThreadGroup中,让调试器可以监视到。

All threads are Linux threads, scheduled by the kernel. They're usually started from managed code (using Thread.start), but they can also be created elsewhere and then attached to the JavaVM. For example, a thread started with pthread_create can be attached with the JNI AttachCurrentThread or AttachCurrentThreadAsDaemonfunctions. Until a thread is attached, it has no JNIEnv, and cannot make JNI calls.

Attaching a natively-created thread causes a java.lang.Thread object to be constructed and added to the "main" ThreadGroup, making it visible to the debugger. Calling AttachCurrentThread on an already-attached thread is a no-op.

Android does not suspend threads executing native code. If garbage collection is in progress, or the debugger has issued a suspend request, Android will pause the thread the next time it makes a JNI call.

Threads attached through JNI must call DetachCurrentThread before they exit. If coding this directly is awkward, in Android 2.0 (Eclair) and higher you can use pthread_key_create to define a destructor function that will be called before the thread exits, and call DetachCurrentThread from there. (Use that key with pthread_setspecific to store the JNIEnv in thread-local-storage; that way it'll be passed into your destructor as the argument.)

3 局部和全局引用

传递到jni函数的参数和返回值都是一个局部引用,生命周期只限于当前native方法中,这个和c++是一样的,在方法内部的局部对象一旦在方法执行完毕就会被释放。这些对象包括jobect及其子类,像jclass,jstring 和jarray。如果想要将局部引用变成全局的,就要用NewGlobalRef或者NewWeakGlobalRef方法了。因此native方法内部jstring,jarray等对象不去释放也是可以的,GC是会回收的,但是受限于系统资源限制,推荐使用DeleteLocalRef方法去手动释放它

4 native方法中通过NewStringUTF或者NewFloatArray之类申请的对象需要手动释放吗?

不需要,但是使用DeleLocalRef释放更好

5 GetStringUTFChars或GetByteArrayElements获取的数据指针需要释放吗?

需要,调用这两个方法获取数据指针后,必须要ReleaseStringUTFChars或者ReleaseByteArrayElements,他会告诉GC,可以对对象进行正常gc操作了,否则GC不确定当前指针还在有效期,就提前回收,会照成事故的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值