c++调用java 内存泄露的问题
各位大侠,最近需要用c++调用java,然后自己看了看jni相关的东西,写了下,能运行,不过会内存泄露,我检查了下,new了的都delete了,java那边单独测试是不会内存泄露的,大家能不能帮我看看啊
网上看了好多东西,那个IBM有关jni的教程我也看了,说注意要DeleteLocalRef,我也是这样做了,但是就是内存涨的特别厉害,平均5秒就涨1M,我都无语了。各位能不能抽出宝贵的时间帮小弟看看啊,谢过了~~~还有两天就得交程序了~~
#include "cJava.h"
#include <sstream>
extern "C"
using namespace std;
namespace cJava {
ncIdentify::ncIdentify(JavaVM* myncjvm)
{
ncjvm = myncjvm;
JavaVMOption options[2];
ncenv = NULL;
JavaVMInitArgs vm_args;
long status;
options[0].optionString = "-Djava.compiler=NONE";
options[1].optionString = "-Djava.class.path=.:../lib/NCnotDep.jar:../lib/CRFPP.jar";
vm_args.version = JNI_VERSION_1_2; // JDK版本号
vm_args.nOptions = 2;
vm_args.options = options;
status = JNI_CreateJavaVM(&ncjvm, (void**)&ncenv, &vm_args);
if(status!=JNI_ERR)
{
cout<<"createJVM is OK"<<endl;
}
else
{
cout<<"creatJVM is fail"<<endl;
}
nccls = ncenv->FindClass("userinterface/NCidentify");
cout<<"findClass is OK in c++"<<endl;
if(nccls !=0){
// 调用string
jmethodID mid = ncenv->GetMethodID(nccls,"<init>","()V");
ncjobj = ncenv->NewObject(nccls,mid);
jmethodID midload = ncenv->GetMethodID(nccls,"loadResource","()V");
ncenv->CallObjectMethod(ncjobj,midload);
}
}
ncIdentify::~ncIdentify()
{
ncenv->DeleteLocalRef(ncjobj);
ncenv->DeleteLocalRef(nccls);
ncjvm->DestroyJavaVM();
}
string ncIdentify::getNCresult(string query)
{
string result;
jclass strClass = ncenv->FindClass("java/lang/String");
jmethodID ctorID = ncenv->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
/*char*转jstring*/
jbyteArray bytes = ncenv->NewByteArray(strlen(query.c_str()));
ncenv->SetByteArrayRegion(bytes, 0, strlen(query.c_str()), (jbyte*)query.c_str());
jstring encoding = ncenv->NewStringUTF("gbk");//utf-8
jstring queryJstr = (jstring)ncenv->NewObject(strClass, ctorID, bytes, encoding);
ncenv->DeleteLocalRef(bytes);
jmethodID ncRegMid= ncenv->GetMethodID(nccls,"runNotDep","(Ljava/lang/String;)Ljava/lang/String;");//这里调用java里的一个函数
jstring msg = (jstring)ncenv->CallObjectMethod(ncjobj,ncRegMid,queryJstr);
/*jstring转char* */
char* rtn = NULL;
jmethodID mid = ncenv->GetMethodID(strClass, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr =(jbyteArray)ncenv->CallObjectMethod(msg,mid,encoding);
jsize alen =(jsize)ncenv->GetArrayLength(barr);
jbyte* ba = ncenv->GetByteArrayElements(barr,JNI_FALSE);
if(alen > 0){
rtn = (char*)malloc(alen+1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
result = rtn;
free(rtn);
}
ncenv->ReleaseByteArrayElements(barr, ba, 0);
ncenv->DeleteLocalRef(encoding);
ncenv->DeleteLocalRef(strClass);
ncenv->DeleteLocalRef(msg);
ncenv->DeleteLocalRef(queryJstr);
return result;
}
}
int main()
{
ifstream reader;
ofstream writer;
string query = "";
string result = "";
char* javaClassPath = "-Djava.class.path=.:../lib/NCnotDep.jar:../lib/CRFPP.jar";
JavaVM* jvm;
cJava::ncIdentify *myiden = new cJava::ncIdentify(jvm);
string fileInName = "/users/testcJava/0-20";
string fileOutName = "/users/testcJava/answer";
string buffer;
reader.open(fileInName.c_str());
writer.open(fileOutName.c_str());
while(getline(reader,query))
{
if(query!="")
{
result = myiden->getNCresult(query);
writer<<result;
writer<<"\n";
}
else
{
writer<<"\n";
}
}
reader.close();
reader.clear();
writer.close();
writer.clear();
delete myiden;
}
[解决办法]
不要做A语言代码修改为B语言代码的无用功。
也不要做用A语言代码直接调用B语言代码库这样复杂、这样容易出错的傻事。
只需让A、B语言代码的输入输出重定向到文本文件,或修改A、B语言代码让其通过文本文件输入输出。
即可很方便地让A、B两种语言之间协调工作。
[解决办法]
可以看看jvm中的global之类的reference是否变化。
楼主在调用java函数的C代码中,需要缓存不会改变的java部分成员函数的handle,不要每次调用都找一次。