Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

  • Java集合

  • Java并发

  • Java IO

    • Java IO概述
    • IO基础

    • 常用IO流

    • 文件与目录操作

    • Java NIO

    • 高级主题

      • RandomAccessFile
      • 内存映射文件MappedByteBuffer
        • 1. 基本概念
        • 2. 创建映射
        • 3. 优势
        • 4. force
        • 5. 释放映射的问题
        • 6. 大文件映射注意点
        • 专家实践清单
        • Tips 快问快答
        • 7. 总结
      • 零拷贝
      • BIO-NIO-AIO模型
      • 字符集与乱码
      • 序列化安全与替代方案
    • 实践与性能优化

    • 面试与设计题

    • IO实践速查

  • JVM

目录

内存映射文件MappedByteBuffer

内存映射文件把文件的一部分或全部映射到进程地址空间中,让程序像访问内存一样访问文件内容。Java 中对应的类是 MappedByteBuffer。

# 1. 基本概念

普通文件读取大致流程:

磁盘 -> 内核缓冲区 -> 用户态 byte[] -> 程序处理

内存映射后:

文件内容 -> 映射到虚拟内存 -> 程序按内存访问

操作系统负责按需加载页面和回写脏页。

# 2. 创建映射

try (FileChannel channel = FileChannel.open(
        Path.of("data.dat"),
        StandardOpenOption.READ,
        StandardOpenOption.WRITE)) {

    MappedByteBuffer buffer = channel.map(
            FileChannel.MapMode.READ_WRITE,
            0,
            channel.size()
    );

    byte first = buffer.get(0);
    buffer.put(0, (byte) 1);
}

映射模式:

  • READ_ONLY:只读。
  • READ_WRITE:读写,修改会反映到文件。
  • PRIVATE:写时复制,修改不一定写回原文件。

# 3. 优势

内存映射适合大文件随机访问,优势包括:

  • 减少显式读写系统调用。
  • 避免频繁从文件流读取到用户数组。
  • 随机访问性能好。
  • 可由操作系统页缓存和预读机制优化。

常见应用:

  • 大文件检索。
  • 数据库和搜索引擎底层存储。
  • 消息队列 CommitLog。
  • 固定格式大文件分析。

# 4. force

MappedByteBuffer.force() 请求把修改刷新到存储设备。

buffer.force();

这不代表业务层已经万无一失。可靠存储仍需考虑写入顺序、校验、崩溃恢复、文件系统语义和硬件缓存。

# 5. 释放映射的问题

MappedByteBuffer 的释放由 JVM 和 Cleaner 机制管理,早期 Java 中没有公开的立即释放 API。文件映射未释放时,某些平台上可能导致文件无法删除或修改。

实践建议:

  • 避免频繁创建短生命周期映射。
  • 映射大文件时按块映射。
  • 重要系统中封装映射管理逻辑。
  • 关注直接内存和虚拟内存使用情况。

# 6. 大文件映射注意点

map 的 size 参数是 long,但单个 MappedByteBuffer 的索引仍受 int 限制。超大文件通常需要分片映射。

第0片:0 ~ 1GB
第1片:1GB ~ 2GB
第2片:2GB ~ 3GB

分片映射要处理跨片读取、边界计算和释放策略。

# 专家实践清单

检查项 建议 风险
文件大小 大文件可分片映射 单次映射过大
访问模式 随机访问收益更明显 顺序小文件收益有限
释放策略 明确生命周期 文件删除或占用问题
一致性 关键数据考虑 force 崩溃后数据未落盘
内存监控 关注堆外内存 排查难度高

内存映射模型:

磁盘文件
  │ mmap
  ▼
虚拟内存区域
  │ page fault / page cache
  ▼
程序像访问内存一样读写

# Tips 快问快答

Q:MappedByteBuffer 是什么? A:把文件的一段内容映射到内存地址空间,像访问内存一样访问文件。

Q:内存映射适合什么场景? A:大文件随机读写、索引文件、只读数据快速访问等。

Q:它一定比普通 IO 快吗? A:不一定,顺序小文件读写未必有明显收益。

Q:映射文件会占用 Java 堆吗? A:主要占用堆外和操作系统虚拟内存,不直接占普通 Java 堆。

Q:为什么释放映射困难? A:映射生命周期受 JVM 和 Cleaner 机制影响,不像普通流立即释放。

Q:force 的作用是什么? A:请求把映射区修改刷回存储设备。

Q:超大文件如何映射? A:通常按片分段映射,并处理跨片边界。

Q:内存映射最大工程风险是什么? A:释放时机、崩溃一致性、堆外内存和跨平台行为。

# 7. 总结

内存映射文件是高性能文件访问的重要技术,特别适合大文件随机读写。但它也带来了资源释放、内存管理、崩溃一致性等复杂问题。业务系统应先确认瓶颈,再引入这类高级能力。

上次更新: 2026/06/25, 14:19:18
RandomAccessFile
零拷贝

← RandomAccessFile 零拷贝→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式