JNI,JNA使用总结

1. GetStringUTFChars与ReleaseStringUTFChars函数简单说明

     通过Jstring返回char *指针,包含结束符

        JNI支持Unicode/UTF-8字符编码互转。Unicode以16-bits值编码;UTF-8是一种以字节为单位变长格式的字符编码,并与7-bitsASCII码兼容。UTF-8字串与C字串一样,以NULL('\0')做结束符, 当UTF-8包含非ASCII码字符时,以'\0'做结束符的规则不变--。7-bit ASCII字符的取值范围在1-127之间,这些字符的值域与UTF-8中相同。当最高位被设置时,表示多字节编码。

//调用GetStringUTFChars,把一个Unicode字串转成UTF-8格式字串  
  1.   
  2. Java_com_conowen_test_testActivity_test(JNIEnv *env, jobject obj, jstring str)  
  3. {  
  4. char buf[128];  
  5. const jbyte *cbyte;  
  6. cbyte= (*env)->GetStringUTFChars(env, str, NULL);  
  7. if (cbyte== NULL) {  
  8. return NULL;  
  9. }  
  10. printf("%s", cbyte);  
  11. (*env)->ReleaseStringUTFChars(env, str, cbyte);  
  12.   
  13. scanf("%127s", buf);  
  14. return (*env)->NewStringUTF(env, buf);  
  15.   
  16. //或者return (*env)->NewStringUTF(env, "hello world");  
  17.  }  
//调用GetStringUTFChars,把一个Unicode字串转成UTF-8格式字串

Java_com_conowen_test_testActivity_test(JNIEnv *env, jobject obj, jstring str)
{
char buf[128];
const jbyte *cbyte;
cbyte= (*env)->GetStringUTFChars(env, str, NULL);
if (cbyte== NULL) {
return NULL;
}
printf("%s", cbyte);
(*env)->ReleaseStringUTFChars(env, str, cbyte);

scanf("%127s", buf);
return (*env)->NewStringUTF(env, buf);

//或者return (*env)->NewStringUTF(env, "hello world");
 }

         上述函数中,有isCopy参数,当该值为JNI_TRUE,将返回str的一个拷贝;为JNI_FALSE将直接指向str的内容。 注意:当isCopy为JNI_FALSE,不要修改返回值,不然将改变java.lang.String的不可变语义。一般会把isCopy设为NULL,不关心Java VM对返回的指针是否直接指向java.lang.String的内容。

         注意:在调用GetStringChars之后,一定要调用ReleaseStringChars做释放,(Unicode -> UTF-8转换的原因)。不管在调用GetStringChars时为isCopy赋值JNI_TRUE还是JNI_FALSE,因不同JavaVM实现的原因,ReleaseStringChars可能释放内存,也可能释放一个内存占用标记。

2. 回调java非静态函数实例

JNIEXPORT jint JNICALL Java_com_kedacom_kdkkdevmgr_commonStatck_CommonStatckSDK_RegAppChannelStatusChangeCBFun
(JNIEnv *pJv, jclass Jc, jobject statusCB, jint nStatusContext)
{
 printf("begin to reg status cb\n");
 if (g_cbData.m_bInit == false)
 {
  g_cbData.m_pEnv = pJv;  
  g_cbData.m_pEnv->GetJavaVM(&g_cbData.m_pJavaVm);
  g_cbData.m_bInit = true;
 }

 g_cbData.m_objStatusCallBack = pJv->NewGlobalRef(statusCB); 
 g_cbData.m_nStatusContext = nStatusContext; 
 jclass cls;
 cls = g_cbData.m_pEnv->GetObjectClass(statusCB);
 if (0 == cls)
 {
  printf("class 0\n");
 }
 g_cbData.m_jStatusCBId = g_cbData.m_pEnv->GetMethodID(cls, "apply", "(IIILjava/lang/String;II)V"); //函数名为apply
 if (g_cbData.m_jStatusCBId == NULL)
 {
  printf("jmidProcess = NULL\n");
  return -2;
 }
 else
 {
  printf("get jmidProcess apply sucess.\n");

 }
 //int i = 10000;  //测试回调
 //jstring jstrChannelID = pJv->NewStringUTF("10086");
 //jstring jstrChannelID = pJv->NewStringUTF("");//不能根据NULL来构造jstring对象,jstring作为java参数的时候不能填入NULL,"",只能填入jstring对象
 //g_cbData.m_pEnv->CallVoidMethod(g_cbData.m_objStatusCallBack, g_cbData.m_jStatusCBId, i, 111, 1, jstrChannelID, 7, 0);

回调时jstring参数不能填NULL,不能根据NULL来构造jstring对象,可以使用""

回调时jbyteArray参数可以填为NULL

3.JNI内存泄露释放

3.1.jstring转换为C风格字符串char* test = (char*)(*env)->GetStringUTFChars(env,jstring,NULL);使用完毕后,应调用:(*env)->ReleaseStringUTFChars(env,jstring, test);释放资源。

4.  在C++中多线程回调java函数

       JNIEnv指针只在它所在的线程中有效,不能跨线程传递和使用。不同线程调用一个本地方法时,传入的JNIEnv指针是不同的。

      局部引用只在创建它们的线程中有效,同样不能跨线程传递。但可以把局部引用转化成全局引用来供多线程使用。

例:

JNIEnv *pJniEnv;
 g_cbData.m_pJavaVm->GetEnv((void **)&pJniEnv, 0x00010006); //JavaVM* m_pJavaVm; //在其他有JNIEnv指针的地方调用 pEnv->GetJavaVM(&g_cbData.m_pJavaVm);初始化JavaVM
 g_cbData.m_pJavaVm->AttachCurrentThread((void**)&pJniEnv, NULL); //AttachCurrentThread并不是加锁的功能
 jstring jstrDeviceID = pJniEnv->NewStringUTF(pszDeviceID);
 jbyte *cXml = (jbyte*)pXmlData;
 jbyteArray chXmlData = pJniEnv->NewByteArray(iXmlDataLen);   
 pJniEnv->SetByteArrayRegion(chXmlData, 0, iXmlDataLen, cXml);
 pJniEnv->CallVoidMethod(g_cbData.m_objDataCallBack,
  g_cbData.m_jDatasCBId,
  lAppChannelID,
  jstrDeviceID,
  iMsgType,
  iSeqID,
  chXmlData,
  iXmlDataLen,
  NULL,
  0,
  iConnIndex); 
 pJniEnv->DeleteLocalRef(jstrDeviceID);
 pJniEnv->DeleteLocalRef(chXmlData);
 g_cbData.m_pJavaVm->DetachCurrentThread();

在c++中new的对象,如果不返回java,必须用release掉,否则内存泄露。包括NewStringUTF,NewObject。如果返回java不必release,java会自己回收。

 
  1. jstring jstr = env->NewStringUTF((*p).sess_id);

  2. ...

  3. env->DeleteLocalRef( jstr);

  4. jobject jobj = env->NewObject(clazz,midInit);

  5. return jobj;


内存泄露可以先从windows资源管理器中,看到随程序运行,内存不断增长的趋势,具体可以用hp jmeter检测。在运行程序时,加jvm参数 -Xrunhprof:heap=all,cutoff=0 ,生成java.hprof.txt,用jmeter打开,Metric -> Residual Objects (Count),可以看到未回收的对象,选中要查看的对象,点Mark记录下要查看的对象,Window -> New Window 打开新窗口,用Metric -> Reference Graph Tree,然后点Find Immediately可以看到对象被哪里引用。


总体原则:释放所有对object的引用

1.FindClass

 
  1. jclass ref= (env)->FindClass("java/lang/String");

  2. env->DeleteLocalRef(ref);


2.NewString / NewStringUTF / NewObject / NewByteArray

例如,

 
  1. jstring (*NewString)(JNIEnv*, const jchar*, jsize);

  2. const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*);

  3. void (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*);

  4. jstring (*NewStringUTF)(JNIEnv*, const char*);

  5. const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*);

  6. void (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*);


env->DeleteLocalRef(ref);

3.GetObjectField/GetObjectClass/GetObjectArrayElement
 

 
  1. jclass ref = env->GetObjectClass(robj);

  2. env->DeleteLocalRef(ref);

 
4.GetByteArrayElements和GetStringUTFChars

 
  1. jbyte* array= (*env)->GetByteArrayElements(env,jarray,&isCopy);

  2. (*env)->ReleaseByteArrayElements(env,jarray,array,0);

  3. const char* input =(*env)->GetStringUTFChars(env,jinput, &isCopy);

  4. (*env)->ReleaseStringUTFChars(env,jinput,input);


5.NewGlobalRef/DeleteGlobalRef
 

 
  1. jobject (*NewGlobalRef)(JNIEnv*, jobject);

  2. void (*DeleteGlobalRef)(JNIEnv*, jobject);


例如,
 

 
  1. jobject ref= env->NewGlobalRef(customObj);

  2. env->DeleteGlobalRef(customObj);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值