当前位置: 首页 > 知识库问答 >
问题:

释放类加载器引用失败

夏雅志
2023-03-14

我将实现一个典型的本机库加载。目标进程:

  1. 从jar中提取本机库
  2. 将其放在唯一的临时目录中
  3. 将本机库加载到JVM

核心问题是删除临时提取的本机库文件。DELETE_ON_EXIT方法不起作用。原因是,如果没有从JVM卸载库,文件就不能删除。但在ClassLoader被垃圾收集之前不会卸载。

我读到的一个提示是使用自定义的ClassLoader(http://www.codethesis.com/blog/unload-java-jni-dll)。我用自定义ClassLoader实现了一个简单的测试,但是它不会垃圾收集自定义ClassLaoder。下面是示例代码:

自定义类装载机

package minloader;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class NativeLibraryLoaderClassLoader extends ClassLoader
{
      @Override
    public Class<?> findClass(final String name) throws ClassNotFoundException 
    {
        try 
        {
            final byte[] classData = loadClassData(name);
            final Class<?> clazz = defineClass(name, classData, 0, classData.length);
            resolveClass(clazz);

            return clazz;
        } 
        catch (final IOException ex) 
        {
            throw new ClassNotFoundException("Class [" + name+ "] could not be found", ex);
        }
    }

    /**
     * Loads the class file into <code>byte[]</code>.
     * @param name The name of the class e.g. de.sitec.nativelibraryloadert.LoadEngine}
     * @return The class file as <code>byte[]</code>
     * @throws IOException If the reading of the class file has failed
     * @since 1.0
     */
    private static byte[] loadClassData(String name) throws IOException 
    {
        try(final BufferedInputStream in = new BufferedInputStream(
                ClassLoader.getSystemResourceAsStream(name.replace(".", "/")
                        + ".class"));
                final ByteArrayOutputStream bos = new ByteArrayOutputStream())
        {
            int i;

            while ((i = in.read()) != -1) 
            {
                bos.write(i);
            }

            return bos.toByteArray();
        }
    }

    @Override
    public String toString() 
    {
        return NativeLibraryLoaderClassLoader.class.getName();
    }

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

本机接口

package minloader;

/**
 *
 * @author RD3
 */
public interface Native
{
    public boolean initializeAPI();
}

原生Impl

package minloader;

public class NativeImpl implements Native
{

    /**
     * Initializes the NativeImpl API
     *
     * @return a boolean to indicate if API is successfully loaded
     */
    @Override
    public boolean initializeAPI(){return true;}

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

package minloader;

/**
 *
 * @author RD3
 */
public class MinLoader
{

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        NativeLibraryLoaderClassLoader nl = null;
        Class pc = null;
        Native pcan = null;
        try
        {
            nl = new NativeLibraryLoaderClassLoader();
            pc = nl.findClass("minloader.NativeImpl");
            pcan = (Native)pc.newInstance();
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
        finally
        {
            System.out.println("CLEAN UP");

            if(pcan != null)
            {
                pcan = null;
            }

            if(pc != null)
            {
                pc = null;
            }
            if(nl != null)
            {
                nl = null;
            }
            System.gc();
            System.gc();
            System.gc();
            try
            {
                Thread.sleep(10);
            }
            catch (InterruptedException ex)
            {
                ex.printStackTrace();
            }
            System.out.println("CLEANED");
        }

        try
        {
            Thread.sleep(10000);
        }
        catch (InterruptedException ex)
        {
            ex.printStackTrace();
        }
        System.out.println("Finished");
    }

}

如果我删除行pcan=(Native)pc.newInstance();然后自定义ClassLoder将垃圾收集。

什么是错的?

问候

共有1个答案

曾嘉荣
2023-03-14

没有办法做你想做的事。您可以尝试在系统之间混合使用runFinalization()调用。gc(),但最终仍然不能保证类加载器将被垃圾收集。

(请注意,直接使用findClass是不方便的。可能您使用findClass是因为该类不是由NativeLibraryLoaderClassLoader实际加载的。这是因为您使用的是无参数ClassLoader构造函数,默认情况下该构造函数将应用程序类装入器用作父类。如果添加NativeLibraryLoaderClassLoader(){super(null);} ,那么您应该能够切换到loadClass。)

 类似资料:
  • 我正在尝试在Spring Boot项目中加载应用程序属性进行测试。我也在使用@DataJpaTest注释。许多人建议使用@TestProperty tySource注释与@datajpaTest的组合,但它不是加载属性。如果我使用@SpringBooTest,它就是加载属性。 我的应用程序属性文件位于主/资源/文件夹中。如果我使用,它正在工作,但我有 这未能使用Spring启动测试进行自动配置。我

  • 框架中所有的类都是通过类加载器(ClassLoader)加载的,通过Loader我们可以实现类的统一管理。下面我们一起来看看Loader提供了哪些加载方法: 1. Loader::import 加载一个类或者加载一个包 方法原型 import( $classPath, $type = IMPORT_APP, $extension=EXT_PHP ) 参数名称 参数说明 $classPath 文件的

  • 加载器,顾名思义,是用于加载元素的,加载的元素可以是库(类),视图文件 , 驱动器 ,辅助函数 , 模型 或其他你自己的文件。 注解 该类由系统自动加载,你无需手工加载。 应用程序"包" 包的视图文件 类参考 应用程序"包" 应用程序包(Package)可以很便捷的将你的应用部署在一个独立的目录中, 以实现自己整套的类库,模型,辅助函数,配置,文件和语言包。 建议将这些应用程序包放置在 appli

  • 在J2EE中,可能无法正常工作。改用。 多少能说明他们在想些什么?这里的“J2EE”环境到底是什么意思?

  • PMD规则如下: 使用合适的类加载器(关键) 在J2EE中,可能无法按预期工作。使用。 你能解释一下他们的想法吗?这里“J2EE”环境的确切含义是什么?

  • 我正试图通过Glide将图像加载到。但是图像没有加载-我得到一个错误。我正在使用以下代码 日志