Разница между ByteBuffer.allocateDirect () и MappedByteBuffer.load () - PullRequest
14 голосов
/ 04 августа 2009

Я пытался реализовать своего рода общий кеш между двумя или более JVM, отображая в памяти определенный файл, используя MappedByteBuffer. Из спецификаций я вижу, что когда мы используем MappedByteBuffer.load(), он должен загружать данные в прямой буфер. У меня есть пара вопросов по этому вопросу.

Мой фрагмент кода ::

RandomAccessFile file = new RandomAccessFile("file.txt","rw");
FileChannel fc = file.getChannel();
MappedByteBuffer buf5 = fc.map(MapMode.READ_WRITE, 0, fc.size());

//ByteBuffer buf6 = ByteBuffer.allocateDirect(100000000);

buf5.load();

try
{
    Class c = Class.forName("java.nio.Bits");
    Field f = c.getDeclaredField("reservedMemory");
    f.setAccessible(true);
    long reservedMemory = f.getLong(null);
    f = c.getDeclaredField("maxMemory");
    f.setAccessible(true);
    System.out.println(
            "Direct Memory Usage: "+ reservedMemory +"/"+ f.getLong(null)+"\n");
}
catch (Throwable t)
{
}
  1. Вывод вышеприведенного кода составляет 0 байт для прямого использования памяти (File.txt равен 1 ГБ). Но если я раскомментирую строку ..

    ByteBuffer buf6 = ByteBuffer.allocateDirect(100000000);
    

    Я получаю прямое использование памяти в 100 МБ. Не в состоянии понять, почему это так, почему я вообще не получаю прямого использования памяти (т. Е. Когда строка закомментирована)

  2. Хотя прямое использование памяти для приведенного выше кода составляет 0 B, я вижу, что резидентная память (с использованием unix top) процесса увеличивается на 1 ГБ. Но если я использую «free -m» на коробке, я не вижу увеличения использования памяти.

В обоих случаях меня немного смущает вопрос о том, где заканчивается память.

Спасибо!

1 Ответ

24 голосов
/ 05 августа 2009

Direct ByteBuffers (те, которые выделены с помощью ByteBuffer.allocateDirect) отличаются от MappedByteBuffers тем, что они представляют разные секции памяти и распределяются по-разному. Direct ByteBuffers - это способ доступа к блоку памяти, выделенному вне JVM, обычно выделяемому с помощью вызова malloc (хотя в большинстве реализаций, вероятно, будет использоваться эффективный распределитель slab). То есть это просто указатель на блок памяти.

MappedByteBuffer представляет раздел памяти, выделенный с помощью вызова mmap , который используется для выполнения ввода-вывода с отображением в памяти. Поэтому MappedByteBuffers не будет регистрировать свое использование памяти так же, как Direct ByteBuffer.

Так что, хотя оба являются «прямыми» в том смысле, что они представляют память вне JVM, их цели различны.

Кроме того, чтобы получить значение reservedMemory, вы рефлексивно вызываете внутренний метод JVM, реализация которого не охватывается какой-либо спецификацией, поэтому нет никаких гарантий относительно того, что это значение возвращает. Прямой ByteBuffers может быть выделен изнутри JNI с использованием NewDirectByteBuffer вызова из C / C ++ (MappedByteBuffers, вероятно, использует это), и это, вероятно, не влияет на значение reservedMemory, которое может быть изменено только при использовании Java ByteBuffer.allocateDirect .

...