About Ashkrit Sharma

Pragmatic software developer who loves practice that makes software development fun and likes to develop high performance & low latency system.

Power of Java MemoryMapped File

Power of Java MemoryMapped File

In JDK 1.4 an interesting feature of Memory mapped file was added to Java, which allows to map any file to OS memory for efficient reading. A memory mapped file can be used to develop an  IPC type of solution. This article is an experiment with memory mapped file to create IPC.

Some details about Memory Mapped File, definition from WIKI

A memory-mapped file is a segment of virtual memory which has been assigned a direct byte-for-byte correlation with some portion of a file or file-like resource. This resource is typically a file that is physically present on-disk, but can also be a device, shared memory object, or other resource that the operating system can reference through a file descriptor. Once present, this correlation between the file and the memory space permits applications to treat the mapped portion as if it were primary memory.

Sample Program

Below we have two Java programs, one is a writer and the other is a reader. The writer is the producer and tries to write to Memory Mapped file, the reader is the consumer and it reads messages from the memory mapped file. This is just a sample program to show you the idea, it does’t handle many edge cases but it is good enough to build something on top of a memory mapped file.

MemoryMapWriter

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class MemoryMapWriter {

 public static void main(String[] args) throws FileNotFoundException, IOException, InterruptedException {
  File f = new File("c:/tmp/mapped.txt");
  f.delete();

  FileChannel fc = new RandomAccessFile(f, "rw").getChannel();

  long bufferSize=8*1000;
  MappedByteBuffer mem =fc.map(FileChannel.MapMode.READ_WRITE, 0, bufferSize);

  int start = 0;
  long counter=1;
  long HUNDREDK=100000;
  long startT = System.currentTimeMillis();
  long noOfMessage = HUNDREDK * 10 * 10; 
  for(;;)
  {         
   if(!mem.hasRemaining())
   {
    start+=mem.position();
    mem =fc.map(FileChannel.MapMode.READ_WRITE, start, bufferSize);
   }
   mem.putLong(counter); 
   counter++;
   if(counter > noOfMessage )
    break; 
  }
  long endT = System.currentTimeMillis();
  long tot = endT - startT;
  System.out.println(String.format("No Of Message %s , Time(ms) %s ",noOfMessage, tot)) ;  
 }

}

MemoryMapReader

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class MemoryMapReader {

 /**
  * @param args
  * @throws IOException 
  * @throws FileNotFoundException 
  * @throws InterruptedException 
  */
 public static void main(String[] args) throws FileNotFoundException, IOException, InterruptedException {

  FileChannel fc = new RandomAccessFile(new File("c:/tmp/mapped.txt"), "rw").getChannel();

  long bufferSize=8*1000;
  MappedByteBuffer mem = fc.map(FileChannel.MapMode.READ_ONLY, 0, bufferSize);
  long oldSize=fc.size();

  long currentPos = 0;
  long xx=currentPos;

  long startTime = System.currentTimeMillis();
  long lastValue=-1;
  for(;;)
  {

   while(mem.hasRemaining())
   {
    lastValue=mem.getLong();
    currentPos +=8;
   }
   if(currentPos < oldSize)
   {

    xx = xx + mem.position();
    mem = fc.map(FileChannel.MapMode.READ_ONLY,xx, bufferSize);
    continue;   
   }
   else
   {
     long end = System.currentTimeMillis();
     long tot = end-startTime;
     System.out.println(String.format("Last Value Read %s , Time(ms) %s ",lastValue, tot));
     System.out.println("Waiting for message");
     while(true)
     {
      long newSize=fc.size();
      if(newSize>oldSize)
      {
       oldSize = newSize;
       xx = xx + mem.position();
       mem = fc.map(FileChannel.MapMode.READ_ONLY,xx , oldSize-xx);
       System.out.println("Got some data");
       break;
      }
     }   
   }

  }

 }

}

Observation

Using a memory mapped file can be a very good option for developing Inter Process communication, throughput is also reasonably well for both produce & consumer. Performance stats by run producer and consumer together:

Each message is one long number

Produce – 10 Million message – 16(s)

Consumer – 10 Million message 0.6(s)

A very simple message is used to show you the idea, but it can be any type of complex message, but when there is complex data structure then serialization can add to overhead. There are many techniques to get over that overhead. More in next blog.

Reference: Power of Java MemoryMapped File from our JCG partner Ashkrit Sharma at the Are you ready blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

4 Responses to "Power of Java MemoryMapped File"

  1. Ashley says:

    Ashkrit,
    Thanks again for a great article. The example is straight forward and very clear.

    A couple of questions:
    1. Are you assuming that MappedByteBuffer is always direct? I read elsewhere http://javarevisited.blogspot.com/2012/01/memorymapped-file-and-io-in-java.html that it can be non-direct also. However, looking at the source code of MappedByteBuffer, it clearly says that its direct buffer backed. A bit confused on that. Could you pls. shed some light on it?

    2. You have spoken about IPC in this article. By giving reading/writing examples in separate files, are you alluding to IPC? What use cases do you see in practical implementation? How will the other process know not to write the same sections of a file as the other process? Is IPC somehow process-safe?

    3. How could you inject the usage of Unsafe for better efficiency here? Would it further enhance performance?

    Thanks again for this article.

  2. Ashkrit says:

    Hi Ashley,

    Thanks for interest in my blog.
    1 – Yes in java MappedByteBuffer is always direct, there is only one implementation(DirectByteBuffer) available in java for MappedByteBuffer. I did cross check in JDK 8, but nothing has changed on this. So it is always direct.

    2 – Yes in the atricle, it is the simple example of IPC. There are many use case of IPC, If you have some producer/consumer type of problem or some kind of request dispatch to service.
    Reliable persistence is one of the very common use case why you will use memorymapped file and then you can some consumer that handles those message.

    ZeroMQ peer to peer message on same box is built using memory mapped files.

    Having multiple writer for memory mapped file can be very tricky because you have to manage everything.
    read & Writes from memorymapped files have same rules as Java memory model, so it is not difficult to build system that does not have to worry about when changes will be visible to other consumer.

    I have not explored the option of injecting Unsafe in memorymapped file, but it will be interesting , if it is possible to do so.

    • maciej says:

      Hi Ashkrit,

      Thanks a lot for a nice intro article on a memory-mapped files in Java. I have the following question for you and a bit of an observation

      If you start with an empty file, and run the reader code only, it will execute the

      FileChannel fc = new RandomAccessFile(new File(“c:/tmp/mapped.txt”), “rw”).getChannel();
      long bufferSize=8*1000;

      MappedByteBuffer mem = fc.map(FileChannel.MapMode.READ_ONLY, 0, bufferSize);

      Which will allocate 1024 bytes, therefore making the buffer filled with 0 bytes. We will read the first 1024 empty bytes until hitting the point when we wait for a new message, which is incorrect in my opinion.

      Also, when we await a new message, it might be the case that the writer maps another 1024 bytes, but does not write anything there yet. The reader would theck the new size, which would be 2048 (as the size is what is currently allocated NOT written by the writer) and it will continue in the same manner, reading empty zeros.

      Is the above the intended behaviour or can we somehow synchronize the reader until some data from writer is actually written?

      • Ashkrit says:

        Hi Maciej,

        Your observation is correct regarding reader, sample program that i used in blog to demonstrate how to use memory mapped file for IPC.

        There are better way to do same thing , ideally index file is used to check whether data is available or not. Write to memorymapped file uses java memory model, so easy to get write guarantee.
        I think i should write blog on this soon.

        I am not sure if you have looked into chronical .
        Chronical is based on memory mapped file and it has some interesting implementation of IPC.

Leave a Reply


× 4 = twelve



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close