如何让JNI在调用本机函数时重新加载共享库?

时间:2012-08-13 17:43:27

标签: java c java-native-interface

背景

我在JAVA中有一个原生函数

package mypackage;

public class MyWrapper {

    private native int
    wrapFilterRawRequest(String config, String rawRequest);

    public void 
    processRequest( String configPath,String rawRequest){
        int status = 0; 
        status = new MyWrapper().wrapFilterRawRequest(configPath, rawRequest);
        status2 = new MyWrapper().wrapFilterRawRequest(configPath, rawRequest);
    }

    static{
        System.loadLibrary("mylibrary");
    }

}

和C中的JNI包装器相同

int processRequest(char *conf, char *req)
{
    int status = 0;   
    // Do something here
    return status;
}

JNIEXPORT jint JNICALL Java_mypackage_MyWrapper_wrapFilterRawRequest
(JNIEnv *env, jobject obj, jstring config, jstring rawRequest)
{
    jint status = 0;

    const char *conf, *req;
    char *conf_copy, *req_copy;

    conf = (env)->GetStringUTFChars(config, NULL);
    req  = (env)->GetStringUTFChars(rawRequest, NULL);

    copy_str(&conf_copy, conf);
    copy_str(&req_copy, req);

    (env)->ReleaseStringUTFChars(config, conf);
    (env)->ReleaseStringUTFChars(rawRequest, req);

    status = processRequest(conf_copy , req_copy );   
    return status;
}

问题

当我在JAVA中两次调用本机函数时,它给了我一个错误,因为它等同于连续两次调用C函数processRequest(char *,char *),这是我的应用程序不支持的。我希望每次都可以独立调用它,类似于运行两次可执行文件时的方式。 (程序在调用两次时有效,但在同一应用程序中调用两次相同的函数时则无效)。我希望JNI在进行本机调用时重新初始化所有内容。我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:5)

嗯,您可以尝试从JVM中卸载dll,方法是使用自己的ClassLoader加载必要的类,执行您需要的操作,将值设置为null,然后调用System.gc()来获取摆脱实例及其dll的旧痕迹,然后通过重新启动实例将dll重新加载到JVM中:

package test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 *
 * @author David
 */
public class Test {

    static {
         System.loadLibrary("mydll.dll");
    }

    @Override
    public void finalize() {
        System.out.println("A garbage collected");
    }

    public void print(String str, int value) {
        System.out.println(str);
        System.out.println(value);
    }

    public static int getNumber() {
        return 42;
    }

    public static void main(String[] args) throws Exception {
        Class<?> clazz = Test.class;//class name goes here
        // static call
        Method getNumber = clazz.getMethod("getNumber");
        int i = (Integer) getNumber.invoke(null /*
                 * static
                 */);
        // instance call
        Constructor<?> ctor = clazz.getConstructor();
        Object instance = ctor.newInstance();
        Method print = clazz.getMethod("print", String.class, Integer.TYPE);
        print.invoke(instance, "Hello, World!", i);
        print = null;
        instance = null;
        ctor = null;
        getNumber = null;
        clazz = null;
        i = 0;
        System.gc();  //reload by empting garbage   Class<?> clazz = Test.class;//class name goes here

        clazz = Test.class;//class name goes here
        // static call
        getNumber = clazz.getMethod("getNumber");
        i = (Integer) getNumber.invoke(null /*
                 * static
                 */);
        // instance call
        ctor = clazz.getConstructor();
        instance = ctor.newInstance();
        print = clazz.getMethod("print", String.class, Integer.TYPE);
        print.invoke(instance, "Hello, World!", i);
        print = null;
        instance = null;
        ctor = null;
        getNumber = null;
        clazz = null;
        i = 0;
        System.gc();  //reload by empting garbage
    }
}

<强>参考: