Bereits mit der Version 1.4 von Java wurde das nio-Paket eingeführt. Dies enthält als Hauptbestandteil Klassen, die einen Buffer, also einen Container für Daten enthalten. Diese Buffer-Implementierungen in Java können für eine sehr effiziente In-Memory-Datenhaltung genutzt werden, insbesondere kann aber auch das in einem vorherigen Artikel bereits vorgestellte Off-Heap-Memory benutzt werden.
Ein Buffer im Heap-Speicher
Im Package java.nio sind verschiedene-Buffer-Implementierungen vorhanden, beispielsweise auch ein ByteBuffer
. Mit diesem können wir nun eine weitere MegyByte-Klassen definieren:
package org.javacream.util.memory; import java.nio.ByteBuffer; public class ByteBufferMegaByte implements MegaByte { private ByteBuffer byteBuffer; public ByteBufferMegaByte(int megaByte) { byteBuffer = ByteBuffer.allocate(megaByte * 1024 * 1024); } @Override public void set(int i, byte value) throws NoSuchFieldException, IllegalAccessException { byteBuffer.put(i, value); } @Override public int get(int i) throws NoSuchFieldException, IllegalAccessException { return byteBuffer.get(i); } @Override public long size() { return byteBuffer.capacity(); } }
Auch hier wird der normale Heap-Speicher der JVM genutzt:
usedMemoryBefore: 1384304, usedMemoryAfter: 526779224
usedMemoryBefore: 1384304, usedMemoryAfterGc: 1385032
Mit einer minimalen Änderung wird nun aber der Buffer-Speicher im Off-Heap genutzt:
byteBuffer = ByteBuffer.allocateDirect(megaByte * 1024 * 1024);
Das nio-API sieht übrigens keine explizite Möglichkeit vor, den Speicher des Buffers wieder freizugeben. Dies übernimmt finalize, eine zugegebenermaßen etwas wacklige und undefinierte Arbeitsweise. Inwieweit zukünftige Java-Versionen hier Abhilfe schaffen ist noch nicht abzusehen.
Quellcode
Der Quellcode der Beispiele ist in einem GitHub-Repository des Autors abgelegt und kann von dort geladen werden.