我將實現典型的本機庫加載。目標進程:發佈ClassLoader引用失敗
- 從罐子中提取本地庫
- 加載本地庫放在一個獨特的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();
。
出了什麼問題?
關於
我已經添加了super(null)的構造函數,並使用loadClass進行了測試,但問題與之前相同。在創建NativeImpl實例後,ClassLoder將永遠不會收集垃圾。 – user3612610 2014-11-24 16:36:53
沒有辦法做你想做的事情。 super(null)的東西是完全不相關的,我只是在你的代碼中突出顯示其他東西,以防你好奇。 – 2014-11-24 22:12:29