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 ...
随机推荐
- Gym100814B Gym100814F Gym100814I(异或) ACM International Collegiate Programming Contest, Egyptian Collegiate Programming Contest (2015) Arab Academy for Science and Technology
今日份的训练题解,今天写出来的题没有昨天多,可能是因为有些事吧... Gym100814B 这个题就是老师改卷子,忘带标准答案了,但是他改了一部分卷子,并且确定自己改的卷子没出错,他想从改过的卷子里把 ...
- 用gcc编译c语言程序以及其编译过程
对于初学c语言编程的我们来说,学会如何使用gcc编译器工具,对理解c语言的执行过程,加深对c语言的理解很重要!!! 1.预编译 --> 2.编译 --> 3.汇编 --> 4.链接- ...
- C语言中%d,%p,%u,%lu等都有什么用处
%d 有符号10进制整数(%ld 长整型,%hd短整型 )%hu 无符号短整形(%u无符号整形,%lu无符号长整形)%i 有符号10进制整数 (%i 和%d 没有区别,%i 是老式写法,都是整型格式) ...
- c语言实现封装、继承和多态
1. 概述 C语言是一种面向过程的程序设计语言,而C++是在C语言基础上衍生来了的面向对象的语言,实际上,很多C++实现的底层是用C语言实现的,如在Visual C++中的Interface其实就是 ...
- .NET MongoDB Driver GridFS 2.2原理及使用示例
一.API解读 1 GridFSBucketOptions 1)public string BucketName { get; set; } 获取或设置bucket名称 2)public int Ch ...
- python 模块中的 __init__.py __main__.py
python中文件夹想作为一个模块被引用,则在文件夹内必须要包含 __init__.py 文件,即使此文件为空. 如果此模块想要运行则必须要包含 __main__.py 文件.接下来说下两个文件起到的 ...
- webpack优化之code splitting
作为当前风头正盛的打包工具,webpack风靡前端界.确实作为引领了一个时代的打包工具,很多方面都带来了颠覆性的改进,让我们更加的感受到自动化的快感.不过最为大家诟病的一点就是用起来太难了. 要想愉快 ...
- tp5 $_ENV获取不到数据
$_ENV变量是取决于服务器的环境变量的,从不同的服务器上获取的$_ENV变量打印出的结果可能是不同的. php的配置文件php.ini的配置项为:variables_order = "GP ...
- file_get_contents("php://input")的使用方法
$data = file_get_contents("php://input"); //input 是个可以访问请求的原始数据的只读流. POST 请求的情况下,最好使用 php: ...
- Jupyter notebook入门
Jupyter notebook入门 [TOC] Jupyter notebook 是一种 Web 应用,能让用户将说明文本.数学方程.代码和可视化内容全部组合到一个易于共享的文档中. Jupyter ...