Разница между ByteBuffer.allocateDirect () и MappedByteBuffer.загружать()


Я пытался реализовать своего рода общий кэш между двумя или более 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 байтам для прямого использования памяти (файл.txt - 1 ГБ). Но если я раскомментирую линию ..

    ByteBuffer buf6 = ByteBuffer.allocateDirect(100000000);
    

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

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

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

Спасибо!

1 14

1 ответ:

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

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

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

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