我将实现典型的本机库加载。目标流程:
核心问题是删除临时提取的本机库文件。 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将被垃圾收集。
有什么问题?
问候
答案 0 :(得分:0)
没有办法做你想做的事。您可以尝试在System.gc()之间混合runFinalization()调用,但最终仍然无法保证ClassLoader将被垃圾回收。
(注意直接使用findClass很笨拙。大概是你正在使用它。因为该类实际上并没有被NativeLibraryLoaderClassLoader加载。那是因为你正在使用no-arg ClassLoader构造函数,默认情况下使用应用程序类加载器作为父项。如果添加NativeLibraryLoaderClassLoader() { super(null); }
,那么您应该可以切换到loadClass。)