Принудительный сборщик мусора для сбора прокси-объектов JNI - PullRequest
2 голосов
/ 10 марта 2010

Несмотря на то, что я делаю все возможное для очистки объектов JNI для освобождения собственной памяти в конце использования, все еще есть некоторые, которые долго остаются без дела, тратя впустую системную память системы.

Есть ли способ заставить GC отдавать приоритет при сборе этих прокси-серверов JNI?

Я имею в виду, есть ли способ заставить GC сконцентрироваться на конкретном объекте, а именно прокси JNI?

Спасибо.

Ответы [ 3 ]

2 голосов
/ 11 марта 2010

Если вы говорите о памяти (и, соответственно, дескрипторах), выделенной в собственном коде, это выходит за рамки сборщика мусора JVM - с этим ничего нельзя поделать, так что вы сами по себе. Если вы не освободите память в нативном коде, когда закончите, она утечет.

Если вы имеете в виду объекты Java, через которые вы получаете доступ к нативному коду, это совершенно обычные объекты, которые будут собраны, когда они станут недоступными. Обратите внимание, что если вы закрепляете объекты Java в собственном коде (например, с помощью GetByteArrayElements), вы также должны освобождать их (например, с помощью ReleaseByteArrayElements).

Если ваш собственный код должен освободить ресурсы перед тем, как вы позволите Java-объекту работать, у Java-объекта должен быть некоторый метод dispose, который при вызове освобождает собственные ресурсы и делает недействительным Java-объект от дальнейшего использования. Просто вызовите метод dispose и отпустите ссылку на объект.

Еще раз, я не знаю, как выгрузить нативную библиотеку после загрузки.

1 голос
/ 27 января 2014

Ваша ментальная модель GC неверна. GC не собирает предметы, а затем освобождает их.

GC собирает живые объекты. Вся остальная память определяется как свободная.

Есть недостатки для объектов с финализаторами и оптимизации для объектов, которые могут быть размещены в стеке и т. Д., Но это правильная ментальная модель.

Глобальные ссылки (постоянная форма ссылок, доступная через JNI) действуют как корни для объектов. GC начинается с корней и рекурсивно следует всем ссылкам при поиске живых объектов. Если глобальная ссылка будет удалена, то она прекратит поддерживать указанный объект живым. GC может затем восстановить память, используемую объектом, но только если нет никаких других ссылок, и только во время последующего сбора. Не существует общего способа восстановить память для какого-либо определенного подмножества объектов.

1 голос
/ 11 апреля 2010

Нет способа заставить ГК "сфокусироваться" на определенных типах объектов. Я предполагаю, что вы очищаетесь в финализаторе, и финализатор запускается, когда:

  • Объект больше недоступен.
  • GC решает очистить поколение, в котором находится JNI-прокси.

Это означает, что для максимально быстрой очистки ресурсов необходимо:

  • Сократите объем ссылок, чтобы ваша программа не цеплялась за них в течение долгого времени. Кроме того, сборка мусора для старых объектов запускается реже, поэтому есть две причины, чтобы они жили как можно короче.
  • Добавьте метод ручной очистки, который клиентский код может вызывать после завершения работы с JNI-прокси - не просто дайте ссылкам рассеяться и дождитесь запуска финализатора.

Пример:

class NativeResource {
    private static native long allocate();
    private static native void release(long handle);
    private final long handle;
    private boolean closed = false;
    public NativeResource(){
        handle = allocate();
    }
    /** Deallocates the native resources associated with this proxy. */
    public void close() { 
        if (closed) throw new IllegalStateException("Already closed");
        release(handle); 
        closed = true;
    }
    protected void finalize() throws Throwable {
        try { 
            if (!closed) release(handle);
        } finally {
            super.finalize();
        }
    }
}

// Usage:
NativeResource nr = new NativeResource();
try {
    // Use the resource for something
} finally {
    nr.close(); // Make sure resource is closed even after exceptions
}
...