可参考: MappedByteBuffer以及ByteBufer的底层原理 概述 Bytebuffer分为两种:间接地和直接的,所谓直接就是指MappedByteBuffer,直接使用内存映射(java MappedByteBuffer 类结构 public abstract class MappedByteBuffer extends ByteBuffer { public final MappedByteBuffer load( ) public final boolean isLoaded( ) public final MappedByteBuffer force( ) } MappedByteBuffer 当用 MappedByteBuffer 对象来更新一个文件,您应该总是使用 MappedByteBuffer.force( )而非 FileChannel.force( ),因为通道对象可能 不清楚通过映射缓冲区做出的文件的全部更改 MappedByteBuffer 没有不更新文件元数据的选项——元数据总是会同时被更新的。
神奇的MappedByteBuffer MappedByteBuffer MappedByteBuffer的最大值 MappedByteBuffer的使用 注意 内部实现 get过程 性能分析 总结 补充 : MappedByteBuffer的释放 ---- Java提供的MappedByteBuffer底层实现靠的是mmap技术,当然这里指的是Linux平台,因此建议大家先了解一下mmap在Linux上的实现原理 ,然后在来阅读本篇文章: Linux mmap原理 ---- MappedByteBuffer MappedByteBuffer就是对mmap的一个java版本封装,在Linux平台,MappedByteBuffer ---- MappedByteBuffer的最大值 既然可以映射到虚拟内存空间,那么这个MappedByteBuffer是不是可以无限大? MappedByteBuffer是没有close方法的,即使它的FileChannel被close了,MappedByteBuffer仍然处于打开状态,只有JVM进行垃圾回收的时候才会被关闭。
到底是 FileChannel 快还是 MappedByteBuffer 快…… 天啊,问题太多了!!!!!! 让我们慢慢分析。 楼主写了一个小项目,用于测试 Java MappedByteBuffer & FileChannel & RandomAccessFile & FileXXXputStream 的读写性能。 使用 1GB 文件进行测试(小文件没有参考意义,大文件 mmap 无法映射) 纯粹读测试 1GB 文件: 测试 MappedByteBuffer & FileChannel & RandomAccessFile 纯粹写测试 1GB 文件: 测试 MappedByteBuffer & FileChannel & RandomAccessFile & FileInputStream. ?
详解MappedByteBuffer 小师妹:MappedByteBuffer听起来好神奇,怎么使用它呢? 我们先来看看MappedByteBuffer的定义: public abstract class MappedByteBuffer extends ByteBuffer 它实际上是一个抽象类 MappedByteBuffer的使用 小师妹,F师兄我们来举两个使用MappedByteBuffer读写的例子吧。 善! 先看一下怎么使用MappedByteBuffer来读数据: ? MappedByteBuffer要注意的事项 小师妹:F师兄,MappedByteBuffer因为使用了内存映射,所以读写的速度都会有所提升。那么我们在使用中应该注意哪些问题呢? MappedByteBuffer是没有close方法的,即使它的FileChannel被close了,MappedByteBuffer仍然处于打开状态,只有JVM进行垃圾回收的时候才会被关闭。
而虚拟内存(MappedByteBuffer)与物理内存之间的关联是通过进程页表来完成的,由于此时内核还未对 MappedByteBuffer 分配物理内存,所以 MappedByteBuffer 在 后续我们对 MappedByteBuffer 的访问速度就变得非常快了,上述针对 MappedByteBuffer 的预热过程,JDK 封装在 MappedByteBuffer#load 方法中: public 3.2 mlock MappedByteBuffer 经过上面 MappedByteBuffer#load 函数的处理之后,现在 MappedByteBuffer 背后所映射的文件内容已经加载到 page 这时如果我们再次访问 MappedByteBuffer 的时候,依然会发生缺页中断,当 MappedByteBuffer 被我们用来实现系统中的核心功能时,这就迫使我们要想办法让 MappedByteBuffer MappedByteBuffer。
详解MappedByteBuffer 小师妹:MappedByteBuffer听起来好神奇,怎么使用它呢? 我们先来看看MappedByteBuffer的定义: public abstract class MappedByteBuffer extends ByteBuffer 它实际上是一个抽象类,具体的实现有两个 MappedByteBuffer的使用 小师妹,F师兄我们来举两个使用MappedByteBuffer读写的例子吧。 善! MappedByteBuffer是没有close方法的,即使它的FileChannel被close了,MappedByteBuffer仍然处于打开状态,只有JVM进行垃圾回收的时候才会被关闭。 总结 本文再次介绍了虚拟地址空间和MappedByteBuffer的使用。
关于 MappedByteBuffer 和 FileChannel 的话题,网上有很多,但大部分都在讨论 MappedByteBuffer 相较于传统 FileChannel 的优势,但好像很少有人来写一写 MappedByteBuffer 的劣势,所以笔者这里想写一点不一样的,来和大家讨论讨论 MappedByteBuffer 的劣势有哪些。 和 MappedByteBuffer 读写文件的流程。 既然 MappedByteBuffer 这么屌,那我们何不干脆在所有文件的读写场景中全部使用 MappedByteBuffer,这样岂不省事 ? MappedByteBuffer。
; // mmap 文件映射操作 MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE 获取消息开始---------- mappedByteBuffer.position(0); mappedByteBuffer.limit(data.length()); ; // mmap 文件映射操作 MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE 获取消息开始---------- mappedByteBuffer.position(0); mappedByteBuffer.limit(data.length()); mappedByteBuffer比直接写入mappedByteBuffer多了很多步骤,再加上发送队列处理事件默认只有200毫秒(waitTimeMillsInSendQueue=200),造成集群不能正常压测的原因
MappedByteBuffer JAVA培训中顺序IO通过MappedByteBuffer实现,与传统IO不同的是,MappedByteBuffer需要使用者提供一个位置(偏移量),详细看以下代码: mappedByteBuffer.position(index);mappedByteBuffer.put(content.getBytes(StandardCharsets.UTF_8)); 代码中可见 ,通过MappedByteBuffer提供的api position();来指定位置(偏移量),put()进行写操作,详细如下。 ,0,size); //3 mappedByteBuffer.position(index); //4mappedByteBuffer.put(content.getBytes(StandardCharsets.UTF 上述代码中标记4位置中,通过MappedByteBuffer对象的position(); API设置写入位置,官方解释如下: Sets this buffer's limit.
MappedByteBuffer mappedByteBuffer = fileChannel.map(mode, position, size); 稍微解释一下 map 方法的三个参数。 mappedByteBuffer = fileChannel.map(MapMode.READ_ONLY, 0, fileChannel.size()); if (mappedByteBuffer MappedByteBuffer mappedByteBuffer = fileChannel.map(MapMode.READ_WRITE, 0, 1024); 这一次,我们把模式调整为 MapMode.READ_WRITE mappedByteBuffer = fileChannel.map(MapMode.READ_WRITE, 0, 1024); if (mappedByteBuffer ! 03、MappedByteBuffer 的遗憾 据说,在 Java 中使用 MappedByteBuffer 是一件非常麻烦并且痛苦的事,主要表现有: 1)一次 map 的大小最好限制在 1.5G 左右
mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, file.length(), UTF8_HEADER_BOM.length ); mappedByteBuffer.put(UTF8_HEADER_BOM); 完整示例: /** * csv写入示例(菩提树下的杨过 http://yjmyzz.cnblogs.com mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, file.length(), UTF8_HEADER_BOM.length ); mappedByteBuffer.put(UTF8_HEADER_BOM); //写入标题栏 mappedByteBuffer = channel.map (FileChannel.MapMode.READ_WRITE, file.length(), header.length); mappedByteBuffer.put(header);
我们可以通过FileChannel.map(MapMode mode, long position, long size)将文件通过关联的文件映射到内存区域,然后就可以通过 MappedByteBuffer byte[] arr = "通过内存映射添加数据".getBytes("utf-8"); /** * map对应的position是映射文件的起始位置,跟MappedByteBuffer 没有任何关系 * map传入的size一定不能小于position+后面添加内容大小,否则会报BufferOverflowException异常 */ MappedByteBuffer 笔者将使用中需要注意的事项已经在代码中做了备注 PS: 1、FileChannel的map方法映射空间不能超过Integer.MAX_VALUE 2、FileChannel.map创建内存映射区域后,该MappedByteBuffer 将不再受对应FileChannel的影响 3、内存映射文件有三种模式:READ_ONLY-只读MappedByteBuffer 的写入方法会报ReadOnlyBufferException异常,调用,READ_WRITE
// 第六步:将分块的字节数组放入到当前位置的缓冲区内 mappedByteBuffer.put(byte[] b); // 第七步:释放缓冲区 // 第八步:检查文件是否全部完成上传 (mappedByteBuffer); } catch (IOException e) { logger.log(Level.SEVERE, "上传大文件出错", // 所以为了系统稳定性释放前一般需要检查是否还有线程在读或写 public static void freedMappedByteBuffer(final MappedByteBuffer mappedByteBuffer mappedByteBuffer.force(); AccessController.doPrivileged(new PrivilegedAction<Object>() { , e); } logger.info("clean MappedByteBuffer completed!!!")
映射字节缓冲区 ( MappedByteBuffer ) I . 缓冲区 ( Buffer ) 存取类型 ---- 1 . 映射字节缓冲区 ( MappedByteBuffer ) ---- 1 . 映射字节缓冲区 ( MappedByteBuffer ) : 在内存中修改文件 , 不需要将文件中的内容拷贝到内存中 , 再修改后 , 写回到文件 , 其性能提高了很多 ; ① 内存说明 : 修改文件的内存并不是堆内存 , 而是在堆外内存中 ; ② MappedByteBuffer 类结构 : MappedByteBuffer 继承 ByteBuffer 抽象类 ; MappedByteBuffer 本身也是抽象类 mappedByteBuffer = fc.map(FileChannel.MapMode.READ_WRITE, 0, 10); mappedByteBuffer.put(
java 为nio的MappedByteBuffer 参考: https://docs.oracle.com/javase/7/docs/api/java/nio/ MappedByteBuffer.html https://javadoc.scijava.org/Java9/java/nio/MappedByteBuffer.html linux tmp_buf File("file.txt"); long len = file.length(); byte[] ds = new byte[(int)len]; //mappedByteBuffer 为零拷贝 MappedByteBuffer mappedByteBuffer = new FileInputStream(file). FileChannel.MapMode.READ_ONLY,0,len); for (int offset = 0; offset < len; offset++) { byte b = mappedByteBuffer.get
左侧对应 DirectByteBuffer,右侧对应 MappedByteBuffer。 ,直接给出结论,在 GC 发生或者操作系统主动清理时 MappedByteBuffer 会被回收。 但也不是不进行测试,我们会对 MappedByteBuffer 进行更有意思的研究。 CASE 4:手动回收 MappedByteBuffer。 public class MmapUtil { public static void clean(MappedByteBuffer mappedByteBuffer) { ByteBuffer 结论:MappedByteBuffer 映射出一片文件内容之后,不会全部加载到内存中,而是会进行一部分的预读(体现在占用的那 100M 上),MappedByteBuffer 不是文件读写的银弹,它仍然依赖于
2.Index数据结构 写入索引数据到mappedByteBuffer代码 /计算索引数据需要放在哪个位置 int absIndexPos = IndexHeader.INDEX_HEADER_SIZE 中 this.mappedByteBuffer.putInt(absIndexPos, keyHash); //将物理偏移量存储在MappedByteBuffer中 this.mappedByteBuffer.putLong (absIndexPos + 4, phyOffset); //落地时间-当前索引的起始时间差值写入MappedByteBuffer this.mappedByteBuffer.putInt(absIndexPos + 4 + 8, (int) timeDiff); //记录前一条hash桶对应的值(Index条目下标);注意此处用于解决Hash冲突 this.mappedByteBuffer.putInt(absIndexPos + 4 + 8 + 4, slotValue); //将当前index中包含的条目数量存入到Hash槽中,将覆盖原先的值 this.mappedByteBuffer.putInt(absSlotPos
java nio提供的FileChannel提供了map()方法,该方法可以在一个打开的文件和MappedByteBuffer之间建立一个虚拟内存映射,MappedByteBuffer继承于ByteBuffer mappedByteBuffer = new FileInputStream(file).getChannel().map(FileChannel.MapMode.READ_ONLY, 0, len); for (int offset = 0; offset < len; offset++) { byte b = mappedByteBuffer.get ,MappedByteBuffer本身是一个抽象类,其实这里真正实例话出来的是DirectByteBuffer; 2.DirectByteBuffer DirectByteBuffer继承于MappedByteBuffer ,从名字就可以猜测出开辟了一段直接的内存,并不会占用jvm的内存空间;上一节中通过Filechannel映射出的MappedByteBuffer其实际也是DirectByteBuffer,当然除了这种方式
import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer * MappedByteBuffer 对象是直接的,占用的内存位于jvm堆栈之外。 ro = channel.map ( FileChannel.MapMode.READ_ONLY, 0, channel.size( )); MappedByteBuffer = fileLock) { MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, length map(MapMode mode, long position, long size) * size大于文件大小,文件会做扩充 * MappedByteBuffer 内存映射缓冲池
MappedByteBuffer对象有两种方式获得,channel的map()方法返回或者ByteBuffer.allocateDirect(capacity)。 // MappedByteBuffer mappedByteBuffer=fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, file.length ());//将fileChannel全部数据映射到buffer MappedByteBuffer mappedByteBuffer=fileChannel.map(FileChannel.MapMode.READ_ONLY System.out.println(cb); mappedByteBuffer.clear(); mappedByteBuffer=fileChannel.map(FileChannel.MapMode.READ_ONLY MappedByteBuffer,可被通道读写-intsmaze MappedByteBuffer提供的方法: load():加载整个文件到内存 isLoaded():判断文件数据是否全部加载到了内存