jni中java基本类型需用jint、jboolean等专用别名,不可用原生c类型;对象操作须通过jni函数获取id并调用;字符串和数组需注意内存管理与同步;引用需区分本地/全局并正确释放。

Java基本类型在JNI C代码里怎么写
Java的int、boolean这些基本类型,到C里不是直接用int或bool——JNI自己定义了一套固定别名,不匹配就会编译报错或运行时崩溃。
常见错误现象:java.lang.UnsatisfiedLinkError 或 C端读到乱码值,往往是因为用了原生C类型代替JNI类型。
-
jint对应Javaint(别用int,Windows下可能4字节但Linux下不一定) -
jboolean对应boolean,取值只能是JNI_TRUE(1)或JNI_FALSE(0),不能传123或NULL -
jbyte是带符号的8位,Java里byte也是带符号的,这点容易被忽略,误当成无符号处理 -
jlong必须用long long接收(64位),在32位平台尤其要注意对齐和printf格式符(得用"%lld")
Java对象怎么在C里拿到字段和方法
不能直接访问Java对象内存,必须通过JNI函数间接操作。对象在C里只是一个jobject句柄,没类型信息,也不支持强制转换。
使用场景:想从C里读String内容、调用某个ArrayList.add()、或者修改自定义类的public int count字段。
立即学习“Java免费学习笔记(深入)”;
- 字符串要用
GetStringUTFChars()或GetStringUTFRegion(),用完必须配对调用ReleaseStringUTFChars(),否则内存泄漏 - 获取字段ID用
GetFieldID(),注意签名字符串要严格匹配,比如"I"是int,"Ljava/lang/String;"才是String,少个分号或大小写错就返回NULL - 调用实例方法前,先用
GetMethodID()拿ID,再用CallVoidMethod()这类函数;静态方法用GetStaticMethodID()+CallStaticXXXMethod() - 所有
FindClass()返回的jclass都建议缓存,频繁调用会触发类加载开销
数组怎么在Java和C之间传递
数组不是指针,不能直接memcpy。JNI提供两套路径:拷贝副本(安全但慢)或获取直接缓冲区(快但需手动同步)。
性能影响明显:小数组用GetIntArrayElements()够用;大图像/音频数据必须用GetPrimitiveArrayCritical()或直接ByteBuffer + GetDirectBufferAddress()。
-
GetIntArrayElements()可能返回副本,也可能是原始地址,取决于JVM实现,所以必须用ReleaseIntArrayElements()通知是否修改过 - 如果Java端用了
ByteBuffer.allocateDirect(),C里可用GetDirectBufferAddress()拿到裸指针,零拷贝,但Java端GC不会管这块内存,C写越界=崩溃 - 对象数组(如
String[])不能用primitive系列函数,得用GetObjectArrayElement()逐个取jobject,再分别处理
本地引用和全局引用容易漏掉哪几处
JNI引用不是C指针,是JVM管理的句柄。本地引用(local reference)在JNI函数返回后自动释放,但一旦跨函数保存或存入全局变量,就必须转成全局引用(global reference),否则下次调用时jobject已失效。
最容易踩的坑:在C里开新线程处理Java对象,或把jobject存在static变量里,却没做NewGlobalRef()。
- 所有从JNI函数返回的
jobject、jclass、jstring等,默认都是本地引用,生命周期只到当前JNI函数结束 - 需要长期持有时,必须调用
NewGlobalRef(),用完记得DeleteGlobalRef(),否则Java对象永远无法被GC回收 - 局部引用数量有上限(通常512),大量循环创建
jstring又不及时DeleteLocalRef(),会触发OutOfMemoryError: Cannot allocate new local reference -
FindClass()返回的jclass也是本地引用,缓存前务必转成全局引用
JNI映射看着是类型对照表,实际是两套内存模型之间的协议。类型写错、引用没管住、字符串没释放——这些问题不会立刻报错,而是在特定设备、特定JVM版本、特定负载下突然崩掉。










