DirectByteBuffer in Java

MappedByteBuffer is a way to read and write binary files directly in Java. It allows you to address file data at the bytes level, so it is convenient and potentially high performance.

It maps a file region into the virtual address space of the Java process. Here's a simple example of how to use it (also on GitHub):

public class MappedByteBufferTest { 
      public static void main(String[] args) throws IOException { 
          //WRITE FILE 
          int len = 200; 
          RandomAccessFile file = new RandomAccessFile("output.txt", "rw");         
          MappedByteBuffer outputBuffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, len); 
          for (int i = 0; i < len; i++) 
              outputBuffer.put((byte) i); 

          //READ FILE 
          FileInputStream inputStream = new FileInputStream("output.txt"); 
          MappedByteBuffer mappedByteBuffer = inputStream.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, len); 
          for (int i = 0; i < len; i++) { 
              if(mappedByteBuffer.get(i) != (byte) i) 
                   throw new IOException("oops"); 
          } 
          ((sun.nio.ch.DirectBuffer) mappedByteBuffer).cleaner().clean(); 
      } 



On further thought, there seems to be a problem with this class. There's no public API to unmap the file out of the process address space. This will cause issues on Windows, which locks the file and the mapped region. While examining the instance of the class under the IntelliJ debugger, I noticed the private field called cleaner.






This piqued my interest on how to use the cleaner. By studying the source code of the openJDK, I learned that MappedByteBuffer is a subclass of sun.nio.ch.DirectBuffer. Each unmapped region is associated with a thread. Though it seems like an overkill, this allows to automatically unmap the region (though nondeterministically). The following code snippet will force the cleaner thread to run:
        ((sun.nio.ch.DirectBuffer) mappedByteBuffer).cleaner().clean();

Out of curiosity, I did some Googling to see if there is an issue with this nondeterministic behavior. I found an interesting example. Kafka is a distributed program for sending and receiving messages. It seems to be a pretty simple case. I created a pull request with my limited knowledge of Scala.

Popular posts from this blog

Space Race: a simple Rust game built on the Bevy framework

Building a Toy Language Compiler in Go

tldr: Raft + Implementation Tips