Разница между ByteBuffer.allocateDirect() и MappedByteBuffer.load()

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

    ByteBuffer buf6 = ByteBuffer.allocateDirect(100000000);
    

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

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

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

Спасибо!

Ответы

Ответ 1

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

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

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

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