2014-11-21 101 views
1

我將實現典型的本機庫加載。目標進程:發佈ClassLoader引用失敗

  1. 從罐子中提取本地庫
  2. 加載本地庫放在一個獨特的Temp目錄JVM

的核心問題是暫時性的移除提取本地庫文件。 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(); 
} 

本地默認地將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"); 
    } 

} 

如果我刪除然後將自定義ClassLoder將垃圾收集線pcan = (Native)pc.newInstance();

出了什麼問題?

關於

回答

0

沒有辦法做你正在做的事情。您可以嘗試在System.gc()之間混用runFinalization()調用,但最終仍不能保證ClassLoader將被垃圾收集。 (請注意,直接使用findClass會很麻煩,大概你使用的是因爲這個類實際上並沒有被NativeLibraryLoaderClassLoader加載,這是因爲你使用了無參數的ClassLoader構造函數,它使用了應用程序類加載器如果您添加NativeLibraryLoaderClassLoader() { super(null); },那麼您應該能夠切換到loadClass。)

+0

我已經添加了super(null)的構造函數,並使用loadClass進行了測試,但問題與之前相同。在創建NativeImpl實例後,ClassLoder將永遠不會收集垃圾。 – user3612610 2014-11-24 16:36:53

+0

沒有辦法做你想做的事情。 super(null)的東西是完全不相關的,我只是在你的代碼中突出顯示其他東西,以防你好奇。 – 2014-11-24 22:12:29