各位大侠,最近需要用c++调用java,然后自己看了看jni相关的东西,写了下,能运行,不过会内存泄露,我检查了下,new了的都delete了,java那边单独测试是不会内存泄露的,大家能不能帮我看看啊#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;
}网上看了好多东西,说注意要DeleteLocalRef,我也是这样做了,但是就是内存涨的特别厉害,平均5秒就涨1M,我都无语了。各位能不能抽出宝贵的时间帮小弟看看啊,谢过了~~~还有两天就得交程序了~~

解决方案 »

  1.   


    #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;
    }
      

  2.   

    亲,有人解答么?帮我看看吧,网上那个IBM有关jni的教程我也看了,还是找不出问题来啊
      

  3.   

    我又添了些注释,大家帮忙看看吧,自己实在是解决不了了~~谢了哈
    #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;
    }
      

  4.   

    我也不想,前人用java写的一个工具,客户执意要用c++,我的程序里需要调这个工具,这个工具太复杂了所以来不及用c++重写了,所以就直接用c++调用封装好了的jar了
      

  5.   

    真不好意思,木有搞度偶,帮不到你.java有jvm自动管理内存。
    c++是不是有些内存没有释放掉。
      

  6.   

    jni内存有一个特性,如果你是在java中声明的内存,如果没有返回给C/C++模块,JAVA会自己处理掉那部分内存,如果JAVA吧这个数据给了C/C++,那么需要C/C++里面来手动回收内存(手动回收的方式差jni文档),如果是C++建立的数据传给JAVA,然后C没有再接触到这个数据,那么java会回收掉,如果C建立了数据传给java,然而C有再持有数据,那么C需要自己回收。
      

  7.   

    关于数据流转的特性,这需要你自己把握了,最后,不要随便回收掉数据,如果在java使用数据时回收数据,JVM会感受不到数据被回收,那么会导致JVM崩溃,而不是异常,这个要注意,因为C的操作不在jvm管辖范围内,任何不慎操作都会导致jvm崩溃,因此jni开发的难度是很大的。
      

  8.   

    恩,以前刚开始写这些代码的时候就经常遇到jvm崩溃啊,现在总算能运行了,结果内存不停的涨啊,控制不住啊