Java MemoryMapped文件的功能
在JDK 1.4中,将内存映射文件的有趣功能添加到Java中,该功能允许将任何文件映射到OS内存以进行有效读取。 内存映射文件可用于开发IPC类型的解决方案。 本文是使用内存映射文件创建IPC的实验。
有关内存映射文件的一些详细信息,来自WIKI的定义
内存映射文件是虚拟内存的一部分,已为其分配了与文件或类文件资源的某些部分直接的逐字节关联。 此资源通常是物理上存在于磁盘上的文件,但也可以是设备,共享内存对象或操作系统可以通过文件描述符引用的其他资源。 一旦存在,文件和内存空间之间的这种关联关系允许应用程序将映射的部分当作主内存一样对待。
样例程序
下面我们有两个Java程序,一个是作者,另一个是读者。 写入者是生产者,尝试写入“内存映射”文件,读取者是使用者,它从内存映射文件中读取消息。 这只是一个示例程序,向您展示了这个想法,它不能处理许多极端情况,但足以在内存映射文件的顶部构建内容。
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;}} }}}}
观察
使用内存映射文件对于开发进程间通信可能是一个很好的选择,对于生产者和消费者而言,吞吐量也相当不错。 由生产者和消费者共同运行的性能统计信息:
每条消息是一个长号
产生– 1000万条消息– 16个
消费者– 1000万条消息0.6(s)
一条非常简单的消息用于说明您的想法,但是它可以是任何类型的复杂消息,但是当存在复杂的数据结构时,序列化会增加开销。 有许多技术可以克服这些开销。 下一个博客中的更多内容。
翻译自: https://www.javacodegeeks.com/2013/05/power-of-java-memorymapped-file.html