Примеры принудительного освобождения родной памяти, выделенной прямым ByteBuffer, используя sun.misc.Unsafe? - PullRequest
21 голосов
/ 11 декабря 2011

JDK предоставляет возможность выделять так называемые прямые ByteBuffers, где память выделяется вне кучи Java.Это может быть полезно, поскольку сборщик мусора не затрагивает эту память и, как таковой, не влияет на издержки GC: это очень полезно для свойства для долгоживущих вещей, таких как кеши.

Однако есть одинкритическая проблема с существующей реализацией: основная память выделяется асинхронно только тогда, когда владеющий ByteBuffer собирается мусором;нет способа форсировать раннее освобождение.Это может быть проблематично, поскольку на сам цикл GC не влияет обработка ByteBuffers, и, учитывая, что ByteBuffers, скорее всего, находятся в области памяти старого поколения, возможно, что GC вызывается через несколько часов после того, как ByteBuffer больше не используется.

Но теоретически должно быть возможно использовать sun.misc.Unsafe методы (freeMemory, allocateMemory) напрямую: это то, что сам JDK использует для выделения / освобождения собственной памяти.Глядя на код, одна потенциальная проблема, которую я вижу, это возможность двойного освобождения памяти, поэтому я хотел бы убедиться, что состояние будет очищено должным образом.

Может кто-нибудь указать мне на код, который делает это?В идеале хотелось бы использовать это вместо JNA.

ПРИМЕЧАНИЕ: я видел этот вопрос , который как бы связан.

Похоже, что указанные ответы являются хорошим способомgo: здесь - пример кода из Elastic Search, который использует эту идею.Спасибо всем!

Ответы [ 3 ]

25 голосов
/ 11 декабря 2011

Существует гораздо более простой способ очистки памяти.

public static void clean(ByteBuffer bb) {
    if(bb == null) return;
    Cleaner cleaner = ((DirectBuffer) bb).cleaner();
    if (cleaner != null) cleaner.clean();
}

Использование этого может иметь большое значение, если вы довольно быстро отбрасываете прямой или отображенный в памяти ByteBuffer.

Одна из причин использования Cleaner для этого заключается в том, что вы можете иметь несколько копий базовых ресурсов памяти, например, с ломтиком (). и У уборщика есть подсчет ресурсов из них.

5 голосов
/ 11 декабря 2011

Использование sun.misc.Unsafe вряд ли возможно, поскольку базовый адрес выделенной собственной памяти является локальной переменной конструктора java.nio.DirectByteBuffer.

На самом деле вы можете принудительно освободить собственную память с помощью следующего кода:

import sun.misc.Cleaner;

import java.lang.reflect.Field;
import java.nio.ByteBuffer;

...

public static void main(String[] args) throws Exception {
    ByteBuffer direct = ByteBuffer.allocateDirect(1024);
    Field cleanerField = direct.getClass().getDeclaredField("cleaner");
    cleanerField.setAccessible(true);
    Cleaner cleaner = (Cleaner) cleanerField.get(direct);
    cleaner.clean();
}
2 голосов
/ 11 декабря 2011

В основном вы хотите следовать той же семантике, что и при использовании потоков ввода-вывода.Точно так же, как вам нужно закрыть поток один раз, вам нужно освободить память один раз.Таким образом, вы можете написать свою собственную обертку вокруг родных вызовов, делая возможным раннее освобождение памяти

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...