发布ClassLoader引用失败

时间:2014-11-21 17:11:53

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

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

  1. 从jar
  2. 中提取本机库
  3. 将其放入一个独特的临时目录
  4. 将本机库加载到JVM
  5. 核心问题是删除临时提取的本机库文件。 DELETE_ON_EXIT方法不起作用。原因是,如果没有从JVM卸载库,则无法删除文件。但是在ClassLoader被垃圾收集之前不会被卸载。

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

    自定义ClassLoader

    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();
    }
    

    Native 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 个答案:

答案 0 :(得分:0)

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

(注意直接使用findClass很笨拙。大概是你正在使用它。因为该类实际上并没有被NativeLibraryLoaderClassLoader加载。那是因为你正在使用no-arg ClassLoader构造函数,默认情况下使用应用程序类加载器作为父项。如果添加NativeLibraryLoaderClassLoader() { super(null); },那么您应该可以切换到loadClass。)