c++调用java 内存泄露的问题

wang19890808 2012-03-02 11:05:26
各位大侠,最近需要用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;
}
...全文
425 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2013-12-12
  • 打赏
  • 举报
回复
不要做A语言代码修改为B语言代码的无用功。 也不要做用A语言代码直接调用B语言代码库这样复杂、这样容易出错的傻事。 只需让A、B语言代码的输入输出重定向到文本文件,或修改A、B语言代码让其通过文本文件输入输出。 即可很方便地让A、B两种语言之间协调工作。
tianya0370 2013-12-12
  • 打赏
  • 举报
回复
我也碰到了同样的问题不知道楼主有没有解决?
wang19890808 2013-12-12
  • 打赏
  • 举报
回复
呵呵,好久没上csdn了,问题早已经解决了,散分啦。不过想想当时调试的时候确实很费劲,具体怎么解决的我忘了,一年前的事了。遇到这种问题一般有两个可能,要么reference申请了没有释放,要么就是构建数组后申请的空间没有释放,我当时是把程序分段测试,用top观察内存的使用情况,直到精确定位到某一行代码了,虽然费劲,但是最后还是解决了。
derekrose 2013-12-12
  • 打赏
  • 举报
回复
并不一定是内存泄露
昵称很不好取 2013-12-12
  • 打赏
  • 举报
回复
可以看看jvm中的global之类的reference是否变化。 楼主在调用java函数的C代码中,需要缓存不会改变的java部分成员函数的handle,不要每次调用都找一次。
东莞某某某 2012-03-03
  • 打赏
  • 举报
回复
不懂这种调用,楼主借助windbg调下吧,怀疑是句柄泄露引起的
wang19890808 2012-03-03
  • 打赏
  • 举报
回复
呵呵,java那部分代码我测试了,是没有问题的,我做java测试的时候是循环调用runNotDep这个方法,刚开始内存会涨,一会就降了,然后就稳定不变了,所以java这边是没有问题的。java那边的代码挺多的,毕竟感觉版面空间有限就没有贴,不好意思了。因为比较急,所以注释没有很详细的添加,我把注释再加详细点吧,你帮我再看看吧[Quote=引用 1 楼 czh3642210 的回复:]

不光要有c程序,还要有要调用的java程序的代码,这样才能看的出来,而且楼主,你可以添加些注释,有利于别人帮忙解决问题。。。如果你需要别人帮忙解决的话。。。
[/Quote]
#include "cJava.h"
#include <sstream>

extern "C"
using namespace std;

namespace cJava {
//初始化java虚拟机
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");//找到java的NCidentify这个类
cout<<"findClass is OK in c++"<<endl;
if(nccls !=0){
// 调用string
jmethodID mid = ncenv->GetMethodID(nccls,"<init>","()V");//调用NCidentify的构造函数
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();//销毁jvm

}

//这是要用到的主体函数了
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,把gbk编码的字符串转化成jstring,以便java函数调用*/
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");//gbk编码
jstring queryJstr = (jstring)ncenv->NewObject(strClass, ctorID, bytes, encoding);//得到jstring
ncenv->DeleteLocalRef(bytes);
jmethodID ncRegMid= ncenv->GetMethodID(nccls,"runNotDep","(Ljava/lang/String;)Ljava/lang/String;");//这里调用java里的一个函数
/*实际上这样理解java的方法就行,输入是string,处理后得到string
反映到这里就是输入一个jstring,得到一个jstring*/
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);//开始释放localref
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;
}



大家都帮忙看看吧,有什么不清楚的一起讨论下,先谢了~~
面包大师 2012-03-03
  • 打赏
  • 举报
回复
不光要有c程序,还要有要调用的java程序的代码,这样才能看的出来,而且楼主,你可以添加些注释,有利于别人帮忙解决问题。。。如果你需要别人帮忙解决的话。。。

64,649

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧