记录一下解决 xxx.dll is already loaded in another classloader

参考的相关资料如下:

1、java 动态库卸载_java 卸载动态链接库 - 全栈程序员必看 (javaforall.cn)

2、java的类加载器以及如何自定义类加载器_磊哥 低调的博客-CSDN博客

3、Java 避免多次动态链接库(dll或.so)_风知前的博客-CSDN博客

4、java - 如何获取已加载的 JNI 库列表?- 堆栈溢出 (stackoverflow.com)

思路如下:

加载dll的时候定义一个变量,在同一个jvm里,别的classloader使用system.load加载前,判断一下这个变量的值。第二次加载的时候,把加载的 dll 删除,然后再重新加载,就不会有重复加载的问题了。

目前还有一个问题是获取到加载的该dll 的classloader,还没找到办法 T-T

代码如下

package test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Vector;
import java.util.concurrent.TimeUnit;

public class TestCall {
    public static final String CHR = null;

    public static void main(String[] args) {
        try {
            int a = 0;

            String jPath = System.getProperty("java.class.path");
            System.out.println(jPath);
            String path = "C:\\D\\work\\JNI\\";
            jPath += ";" + path + "test.class";
            System.setProperty("java.class.path", jPath);

//            System.load("C:\\D\\work\\JNI\\MyLog.dll");

            MyClassLoader myClassLoader = new MyClassLoader();
            myClassLoader.setPath(path);
            Class<?> myLog = myClassLoader.loadClass("test");
            System.out.println(myLog.getClassLoader());

            MyClassLoader myClassLoader1 = new MyClassLoader();
            myClassLoader1.setPath(path);
            Class<?> myLog1 = myClassLoader1.loadClass("test");
            System.out.println(myLog1.getClassLoader());

            Object o = myLog.newInstance();
            System.out.println("o run " + o.getClass().getClassLoader());
//            Method m1 = o.getClass().getMethod("show", null);
//            m1.invoke(new Object(), null);

            new TestCall().freeDll("MyLog.dll", myClassLoader);
            new TestCall().freeDll("MyLog", myClassLoader);
            System.setProperty("mylog","false");

            delay(4);

            Object o1 = myLog1.newInstance();
            System.out.println("o1 run " + o1.getClass().getClassLoader());

            System.out.println(TestCall.a);
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    public static void delay(int second) throws InterruptedException {
        for (int i = 1; i <= second; i++) {
            System.out.println(i);
            TimeUnit.SECONDS.sleep(second);
        }
    }

    public static int a = getA();

    public static int getA() {
        return 10;
    }

    public synchronized void freeDll(String dllName, ClassLoader classLoader) {
        try {
//            ClassLoader classLoader = this.getClass().getClassLoader();
            Field field = ClassLoader.class.getDeclaredField("nativeLibraries");
            field.setAccessible(true);
            Vector libs = (Vector) field.get(classLoader);
            Iterator it = libs.iterator();
            Object o;
            while (it.hasNext()) {
                o = it.next();
                Field[] fs = o.getClass().getDeclaredFields();
                boolean hasInit = false;
                for (int k = 0; k < fs.length; k++) {
                    if (fs[k].getName().equals("name")) {
                        fs[k].setAccessible(true);
                        String dllPath = fs[k].get(o).toString();
                        if (dllPath.endsWith(dllName)) {
                            hasInit = true;
                        }
                    }
                }
                if (hasInit) {
                    Method finalize = o.getClass().getDeclaredMethod("finalize", new Class[0]);
                    finalize.setAccessible(true);
                    finalize.invoke(o, new Object[0]);
                    it.remove();
                    libs.remove(o);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值