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 ...
随机推荐
- HDU2289-Cup-二分
Cup Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...
- Bellman-Ford 求含负权最短路
该算法详解请看 https://www.cnblogs.com/tanky_woo/archive/2011/01/17/1937728.html 单源最短路 当图中存在负权边时 迪杰斯特拉就 ...
- string::npos的一些说明
一.定义 std:: string ::npos的定义: static const size_t npos = -1; 表示 size_t 的最大值( Maximum value for size_t ...
- TCP 和 UDP
TCP协议与UDP协议的区别 首先咱们弄清楚,TCP协议和UCP协议与TCP/IP协议的联系,很多人犯糊涂了,一直都是说TCP/IP协议与UDP协议的区别,我觉得这是没有从本质上弄清楚网络通信! ...
- 蓝桥杯 0/1背包问题 (java)
今天第一次接触了0/1背包问题,总结一下,方便以后修改.不对的地方还请大家不啬赐教! 上一个蓝桥杯的例题: 数据规模和约定 代码: import java.util.Scanner; public ...
- [国嵌笔记][031][Bootloader架构设计]
- 关于nginx中不用.htaccess 用在ningx.conf中配置的问题
官网一直出现http://4**.**..7/php/index.php/admin/base/getConfigs报错404错误问题, 问题一:URL重写问题(nginx配置问题) 问题二:vue中 ...
- mysql 分组和聚合函数
mysql 分组和聚合函数 Mysql 聚集函数有5个: 1.COUNT() 记录个数(count(1),count(*)统计表中行数,count(列名)统计列中非null数) 2.MAX() 最大值 ...
- 5分钟学会使用gitlab
第一次接触到gitlab,操作不是很熟练,犯了一堆错,在多次尝试之后,大概了解了流程,这篇文章主要帮助大家快速上手gitlab,如果文章有什么不对的地方,欢迎在评论区留言~ 1.新建项目 首先你得有个 ...
- C# 将Access中时间段条件查询的数据添加到ListView中
C# 将Access中时间段条件查询的数据添加到ListView中 一.让ListView控件显示表头的方法 在窗体中添加ListView 空间,其属性中设置:View属性设置为:Detail,Col ...