NIO内存映射
磁盘的IO因为速度较慢,可能成为系统运行的瓶颈。所以磁盘的IO在操作系统级实现了提前读,延迟写的机制来提升IO的性能。
提前读就是一次读取需求的数据的同时多读接下来的一段数据至OS缓冲区中,延迟写就是待OS缓冲区中的数据到了一定量时一次写入。
Java中的Bufferxxx类也提供了缓冲区来完成提前读的功能,如果下一次需要读的数据已经在缓冲区了,就直接从缓冲区中取数据。
NIO的内存映射不在直接读文件到OS的缓冲区中,而是直接在JVM中为文件分配了一段内存区域,就像直接在内存中读取文件一样。速度较传统的IO要快很多,文件体积较小时速度差异不是很明显,但文件体积较大时速度的差异就会很明显。
package nio; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel; public class MappedByteBufferTest { private static String sourceFileName = "UCS_PM_1.1.5_EN.sql";
private static String dstFileNameByMappedBuffer = "new.sql";
private static String dstFileNameByFileCopy = "new1.sql";
private static String dstFileNameByAllocateDirect = "new2.sql";
private static FileChannel readChannel, writeChannel;
private static long start;
private static long length; public static void main(String[] args) throws Exception {
mapBufferWriteFile(); //使用内存映射流来完成文件复制
testFileCopy(); //使用普通的IO流来完成文件复制
allocateDirectWriteFile(); //使用DirectMemory来完成文件复制
} public static void mapBufferWriteFile() {
try {
start = System.currentTimeMillis();
RandomAccessFile fos = new RandomAccessFile(dstFileNameByMappedBuffer, "rw");
writeChannel = fos.getChannel();
//writeChannel.position(writeChannel.size()); append to file end position RandomAccessFile fis = new RandomAccessFile(sourceFileName, "r");
readChannel = fis.getChannel();
length = readChannel.size();
MappedByteBuffer mbb = readChannel.map(FileChannel.MapMode.READ_ONLY, 0, length);
writeChannel.write(mbb);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
readChannel.close();
writeChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("mapBufferWriteFile:" + (System.currentTimeMillis() - start));
}
} private static void testFileCopy() {
start = System.currentTimeMillis();
BufferedInputStream bis =null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream(sourceFileName));
bos = new BufferedOutputStream(new FileOutputStream(dstFileNameByFileCopy));
byte[] bytes = new byte[1024];
int index = 0;
int b = bis.read();
while(b != -1){
bytes[index] = (byte) b;
index ++;
if(index == 1023){
bos.write(bytes, 0, index);
index = 0;
b = bis.read();
}else{
b = bis.read();
}
}
if(index != 1023){
bos.write(bytes, 0, index);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}finally {
try {
bis.close();
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("testFileCopy:" + (System.currentTimeMillis() - start));
} private static void allocateDirectWriteFile() {
try {
start = System.currentTimeMillis();
RandomAccessFile fos = new RandomAccessFile(dstFileNameByAllocateDirect, "rw");
writeChannel = fos.getChannel(); RandomAccessFile fis = new RandomAccessFile(sourceFileName, "r");
readChannel = fis.getChannel();
length = readChannel.size();
ByteBuffer mbb = ByteBuffer.allocate((int)readChannel.size());
readChannel.read(mbb);
mbb.flip();
writeChannel.write(mbb);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
readChannel.close();
writeChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("allocateDirectWriteFile:" + (System.currentTimeMillis() - start));
}
}
}
NIO中提供了3种内存映射模式,即:只读(readonly)、读写(read_write)、专用(private) ,对于 只读模式来说,如果程序试图进行写操作,则会抛出ReadOnlyBufferException异常;第二种的读写模式表明了通过内存映射文件的方式写或修改文件内容的话是会立刻反映到磁盘文件中去的,别的进程如果共享了同一个映射文件,那么也会立即看到变化。
除了内存映射之外,还有一种快速读取文件的方式,叫做DirectMemory。DirectMemory也是将文件映射到内存中,只不过占用的不再是JVM的内存,而是非JVM的内存。
直接内存DirectMemory的大小默认为 -Xmx 的JVM堆的最大值,但是并不受其限制,而是由JVM参数 MaxDirectMemorySize单独控制。
DirectMemory所占用的内存无法手动的去释放,只能在 JVM执行 full gc 的时候才会被回收,那么如果在其上分配过大的内存空间,那么也将出现 OutofMemoryError。
如果系统中用到了DirectMemory,则一定要监控其使用的情况,否则很容易导致系统运行缓慢。
-Xms -Xmx不只局限于物理内存的大小,而是也综合虚拟内存的大小,JVM会根据电脑虚拟内存的设置来调节。
NIO内存映射的更多相关文章
- Atitit.病毒木马的快速扩散机制原理nio 内存映射MappedByteBuffer
Atitit.病毒木马的快速扩散机制原理nio 内存映射MappedByteBuffer 1. Java NIO(New Input/Output)1 1.1. 变更通知(因为每个事件都需要一个监听者 ...
- Java NIO内存映射---上G大文件处理(转)
林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文主要讲了java中内存映射的原理及过程,与传统IO进行了对比,最后,用实例说明了结果 ...
- Java NIO 内存映射文件
Java NIO 内存映射文件 @author ixenos 文件操作的四大方法 前提:内存的访问速度比磁盘高几个数量级,但是基本的IO操作是直接调用native方法获得驱动和磁盘交互的,IO速度限制 ...
- JAVA NIO 内存映射(转载)
原文地址:http://blog.csdn.net/fcbayernmunchen/article/details/8635427 Java类库中的NIO包相对于IO 包来说有一个新功能是内存 ...
- (转)NIO 内存映射文件
内存映射文件 I/O 是一种读和写文件数据的方法,它可以比常规的基于流或者基于通道的 I/O 快得多. 内存映射文件 I/O 是通过使文件中的数据神奇般地出现为内存数组的内容来完成的.这其初听起来似乎 ...
- JAVA NIO FileChannel 内存映射文件
文件通道总是阻塞式的. 文件通道不能创建,只能通过(RandomAccessFile.FileInputStream.FileOutputStream)getChannel()获得,具有与File ...
- Java NIO之内存映射文件——MappedByteBuffer
大多数操作系统都可以利用虚拟内存实现将一个文件或者文件的一部分"映射"到内存中.然后,这个文件就可以当作是内存数组来访问,这比传统的文件要快得多. 内存映射文件的一个关键优势是操作 ...
- 【JavaNIO的深入研究4】内存映射文件I/O,大文件读写操作,Java nio之MappedByteBuffer,高效文件/内存映射
内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件.有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问.这种解决办法能大大简化修改文件的代码.fileC ...
- NIO之通道(Channel)的原理与获取以及数据传输与内存映射文件
通道(Channel) 由java.nio.channels包定义的,Channel表示IO源与目标打开的连接,Channel类似于传统的“流”,只不过Channel本身不能直接访问数据,Channe ...
随机推荐
- BZOJ 1800: [Ahoi2009]fly 飞行棋【思维题,n^4大暴力】
1800: [Ahoi2009]fly 飞行棋 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1689 Solved: 1335[Submit][St ...
- Big Event in HDU(多重背包套用模板)
http://acm.hdu.edu.cn/showproblem.php?pid=1171 Big Event in HDU Time Limit: 10000/5000 MS (Java/Othe ...
- [国嵌攻略][182][Sqlite嵌入式数据库移植]
数据库系统构成 在计算机系统中,保存数据的方式一般有两种: 1.普通文件方式 2.数据库方式 相比于普通文件方式,使用数据库来管理大批量数据具有更高的效率与安全性. 数据库系统一般由三个部分构成 1. ...
- 浅析const、let与var
以前无论声明变量还是常量,总是使用var一勺端,知道接触了es6之后,发现原来变量.常量的声明其实是很讲究的. 这里简单来谈谈var.const与let. 1.var.var声明的变量没有块级作用域, ...
- php 下载文件的头信息 Determine Content Type
<?php if(!function_exists('mime_content_type')) { function mime_content_type($filename) { $mime_t ...
- 织梦在服务器上面安装的时候一直提示data文件没有权限,可我已经写了权限,还是提示
1.进入服务器,打开IIS,点击相应无权限的文件夹data,然后点击右上角的编辑权限. 2.勾选写入,然后确定即可. 3.织梦一直收到黑客的攻击,这里建议站长朋友设置下权限,来降低织梦系统的危险系数. ...
- [转]【Java】内部类(Inner Class)如何创建(new)
简单来说,内部类(inner class)指那些类定义代码被置于其它类定义中的类:而对于一般的.类定义代码不嵌套在其它类定义中的类,称为顶层(top-level)类.对于一个内部类,包含其定义代码的类 ...
- 007-declare 声明变量的类型
declare [+/-] [选项] 变量名 - 给变量设定类型 + 取消变量的类型 -a 将变量声明为数组型 -i 将变量声明为整形 -x 将变量声明成环境变量 -r 将变量声明为只读变量 -p 显 ...
- RocketMQ-quickstart(批量消费问题)
基本概念: Producer:消息生产者,负责生产消息,一般由业务系统负责生产消息. Consumer:消息消费者,负责消费消息,一般是后台系统负责异步消费. Push Consumer:Consum ...
- set&enum小结(database)
今天发现mysql中有set这种数据类型,工作的业务中也使用到了.网上查阅资料后,小结一下 先总结一下两者的分别 set和enum类似表单中的多选和单选,set和enum在数据库内部是用整数表示的,显 ...