Разница между 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.