java - 发布类加载器引用失败

标签 java garbage-collection java-native-interface classloader

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

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

核心问题是删除临时提取的 native 库文件。 DELETE_ON_EXIT 方法不起作用。原因是,如果库没有从 JVM 中卸载,则文件无法删除。但在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();
}

原生实现

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 将进行垃圾收集。

出了什么问题?

问候

最佳答案

没有办法做你想做的事。您可以尝试在 System.gc() 之间混合 runFinalization() 调用,但最终仍然不能保证 ClassLoader 会被垃圾回收。

(请注意,直接使用 findClass 很尴尬。大概您之所以使用它,是因为该类实际上并未由 NativeLibraryLoaderClassLoader 加载。那是因为您使用的是无参数 ClassLoader 构造函数,该构造函数默认使用应用程序类加载器作为父级。如果您添加 NativeLibraryLoaderClassLoader() { super(null); },那么您应该能够切换到 loadClass。)

关于java - 发布类加载器引用失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27066726/

相关文章:

java - 阿基利安 : Can not run tests from IDE

java - 如何重用异常抛出代码来返回 boolean 值?

java - 查看 Java Mission Control 中垃圾收集器的类型

javascript - 使用嵌套函数进行 JS 垃圾收集

java - 如何自动复制数据到新的RMI线程?

java - 使用JNA检测AppData\LocalLow的位置

java - 线程 "main"javax.net.ssl.SSLHandshakeException : sun. security.validator.ValidatorException 中的异常:找不到受信任的证书

java - mysql写入后立即读取数据?

c# - 从 C# 注册到 'GCAllocationTick_V1' CLR 事件

Javah 工具错误 : Could not find class file for hellojni