Core Java

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.

Ashkrit Sharma

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

9 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Ashley
Ashley
10 years ago

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… Read more »

Ashkrit
10 years ago

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… Read more »

maciej
maciej
10 years ago
Reply to  Ashkrit

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,… Read more »

Ashkrit
10 years ago
Reply to  maciej

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.

MikaelJ
8 years ago

I’d just like to add that I’ve created a library called MappedBus (http://github.com/caplogic/mappedbus) which helps with both the problem of synchronizing a reader with the writer and also allows for multiple Java processes (JVMs) to write records to the same memory mapped file in order. For this it makes use of Unsafe, CAS and volatile fields. The full explanation of how it’s done is at the github page if you’re interested.

Ashkrit
8 years ago
Reply to  MikaelJ

Great, i will have look at it.

sunil
sunil
8 years ago

hi Ashkrit Sharma
i have a use with mmap files for high volume data processing. please drop a mail .kalva@inmobi.com or give me ur mail id i will get in touch with you.

Ram
Ram
6 years ago

It is a good example on the topic to start with.

Hossein
Hossein
5 years ago

I’m using ffmpeg in android project, it wants input and output for processing videos ,but I want the input and output to be buffers (or any thing in memory) ,can you help me how to achieve this? Actually I want to read and write from memory… I think I should get the address of buffers in memory and it is related to mem protocol …. this is one case I think it shows my problem: First I want to extract the frames of a gif Second process each frame with android SDK classes like bitmaps,paints and… Third merge frames and… Read more »

Back to top button