Ссылка на выпуск ClassLoader не выполнена

1

я реализую типичную загрузку загружаемой библиотеки. Целевой процесс:

  1. Извлеките собственную библиотеку из jar
  2. Поместите его в уникальный каталог temp
  3. Загрузите собственную библиотеку в 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();
}

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 будет собирать мусор.

Что не так?

С уважением

Теги:
garbage-collection
jni
classloader

1 ответ

0

Невозможно делать то, что вы пытаетесь сделать. Вы можете попробовать intermixing вызовы runFinalization() между System.gc(), но в конечном итоге все еще нет гарантии, что ClassLoader будет собираться с мусором.

(Обратите внимание, что использование findClass напрямую неудобно. Предположительно, вы используете это, потому что класс в действительности не загружается NativeLibraryLoaderClassLoader. Это потому, что вы используете конструктор no-arg ClassLoader, который по умолчанию использует загрузчик класса приложения как родительский Если вы добавите NativeLibraryLoaderClassLoader() { super(null); }, то вы сможете переключиться на loadClass.)

  • 0
    Я добавил конструктор с super (null) и тест с loadClass, но проблема осталась прежней. ClassLoder никогда не будет собирать мусор после создания экземпляра NativeImpl.
  • 0
    Нет способа сделать то, что вы пытаетесь сделать. Супер (null) вещь совершенно не связана, я просто выделил что-то еще в вашем коде на случай, если вам интересно.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню