我的程序用到了jni
详细说一下
先用几个替代字母:
A:PB程序
B:VC做的DLL
C:JAVA类我用B调用C,用A调用B,第一次在A中调用B时正常,第二次调用就出错,而且是系统级内存不能读的错误,A程序崩溃,重起A再运行还是同样结果。这是怎么回事呢?是不是B中启动的虚拟机出的问题?

解决方案 »

  1.   

    JNI_CreateJavaVM只能调用一次,你把调用的结果保存下来避免多次调用JNI_CreateJavaVM
      

  2.   

    可是如何保存调用的结果呢,dll中不可能保存吧,难道保存到pb中?
      

  3.   

    试试在DLL中定义全局变量保存JavaVM*,在TLS中保存JNIEnv*,
    下面是我在C++ exe中的代码,看看有没有参考作用
    jint create_jvm(JNIEnv **penv,JavaVM **pjvm)
    {
    CComCritSecLock<CComAutoCriticalSection> cs(g_cs);
    //return 0 if success
    THREAD_SPEC static  JNIEnv*  static_env = NULL;
    static  JavaVM*  static_jvm = NULL;
    jint res = JNI_OK;
    if( static_env && static_jvm)
    {
    *pjvm = static_jvm;
    *penv = static_env;
    AtlTrace(_T("%s return at %d,thread id:%d"),__TFUNCTION__,__LINE__,GetCurrentThreadId());
    return res;
    }
    CRegKey reg;
    long lret = reg.Open(HKEY_LOCAL_MACHINE,reg_key_path,KEY_READ);
    TCHAR jar_dir[PATH_LEN];
    std::basic_string<TCHAR> jar_base_dir;
    if(ERROR_SUCCESS==lret)
    {
    ULONG usize = sizeof(jar_dir)/sizeof(jar_dir[0]);
    lret = reg.QueryStringValue("jar_dir",jar_dir,&usize);
    if(lret!=ERROR_SUCCESS||usize<=0 || usize>=sizeof(jar_dir)/sizeof(jar_dir[0]))
    {
    }
    else
    {
    jar_base_dir = jar_dir;
    if(jar_base_dir.length()>0 && end_with(jar_base_dir,_T("\\"))==false)
    jar_base_dir += _T("\\");
    } }
    reg.Close();
    if(jar_base_dir.length()<1)
    jar_base_dir = get_app_dir();
    LPCTSTR jar_files[] = {
    _T("activation.jar"),
    _T("mail.jar"),
    _T("JDAVMail.0.9.006.jar"),
    _T("mailapi.jar"),
    _T("smtp.jar"),
    _T("commons-httpclient-2.0-final.jar"),
    _T("commons-logging.jar"),
    _T("jdom.jar"),
    };
    char chBuf[4096]; 
    memset(chBuf,0,sizeof(chBuf));
    std::string jarfiles;
    std::string missingfile;
    {
    for(int i=0;i < sizeof(jar_files)/sizeof(jar_files[0]);i++)
    {
    std::string filename = jar_base_dir +jar_files[i];
    if(DoesFileExist(filename.c_str())==FALSE)
    {
    missingfile += filename;
    missingfile += ",\n";
    }
    jarfiles += jar_base_dir;
    jarfiles += jar_files[i];
    jarfiles += _T(";");
    }
    }
    if(missingfile.length()>0)
    {
    missingfile = std::string("missing the following files:\n") + missingfile;
    missingfile += "\ncan set registry:";
    missingfile += reg_key_path;
    missingfile += " jar_dir ";
    AfxMessageBox(missingfile.c_str());
    }
    SetEnvironmentVariableA( _T("CLASSPATH"),jarfiles.c_str());
    if(static_jvm)
    {
    *pjvm = static_jvm;
    res = static_jvm->AttachCurrentThread( (void**)&static_env,NULL);
    *penv = static_env;
    AtlTrace(_T("%s attach thread %d return %d"),__TFUNCTION__,GetCurrentThreadId(),res);
    return res;
    }
    //HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment
    std::basic_string<TCHAR> cls_path;
    cls_path += _T("-Djava.class.path=");
    cls_path += jarfiles;
    char buf[PATH_LEN+4096];
    memset(buf,0,sizeof(buf));
    int buf_length = sizeof(buf)/sizeof(buf[0]);
    StringCchPrintfA(buf, sizeof(buf)/sizeof(buf[0]),cls_path.c_str());
    AtlTrace(buf);
    if(jvm_manager.m_jvm_exist)
    {
    JavaVMInitArgs vm_args;
    JavaVMOption options[2];
    options[0].optionString = buf;
    options[0].extraInfo = NULL;
    options[1].optionString = "vfprintf";
    options[1].extraInfo = Log;
    vm_args.version = JNI_VERSION_1_4;
    vm_args.options = options;
    vm_args.nOptions = sizeof(options)/sizeof(options[0]);
    vm_args.ignoreUnrecognized = JNI_FALSE;
    res = JNI_CreateJavaVM(pjvm, (void**)penv, &vm_args);
    static_env = *penv;
    static_jvm = *pjvm;
    return res;
    }
    else
    return JNI_ERR;
    }
      

  4.   

    #define THREAD_SPEC __declspec(thread)
      

  5.   

    请问需不需要DestroyJavaVM  呢?而且我发现一调用DestroyJavaVM()就出错,为什么?
      

  6.   

    DestroyJavaVM好像sun没有实现,1.42还没有实现,你可以找找1.5的说明
      

  7.   

    我最终也没有使用DestroyJavaVM,在DLL中定义了全局变量保存JavaVM*和JNIEnv*,而且我观察主程序关闭的时候,jvm也释放了。这样程序运行还比较稳定的。多谢了