当前位置: 首页 > news >正文

Java NIO Buffer概念

针对每一种基本类型的 Buffer ,NIO 又根据 Buffer 背后的数据存储内存不同分为了:HeapBuffer,DirectBuffer,MappedBuffer。

HeapBuffer 顾名思义它背后的存储内存是在 JVM 堆中分配,在堆中分配一个数组用来存放 Buffer 中的数据。

public abstract class ByteBufferextends Bufferimplements Comparable<ByteBuffer>
{// Cached array base offsetprivate static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);// These fields are declared here rather than in Heap-X-Buffer in order to// reduce the number of virtual method invocations needed to access these// values, which is especially costly when coding small buffers.//// 在堆中使用一个数组存放Buffer数据final byte[] hb;                  // Non-null only for heap buffers
}

DirectBuffer 背后的存储内存是在堆外内存中分配,MappedBuffer 是通过内存文件映射将文件中的内容直接映射到堆外内存中,其本质也是一个 DirectBuffer 。

由于 DirectBuffer 和 MappedBuffer 背后的存储内存是在堆外内存中分配,不受 JVM 管理,所以不能用一个 Java 基本类型的数组表示,而是直接记录这段堆外内存的起始地址。

public abstract class Buffer {...// Used by heap byte buffers or direct buffers with Unsafe access// For heap byte buffers this field will be the address relative to the// array base address and offset into that array. The address might// not align on a word boundary for slices, nor align at a long word// (8 byte) boundary for byte[] allocations on 32-bit systems.// For direct buffers it is the start address of the memory region. The// address might not align on a word boundary for slices, nor when created// using JNI, see NewDirectByteBuffer(void*, long).// Should ideally be declared final// NOTE: hoisted here for speed in JNI GetDirectBufferAddress// //堆外内存地址long address;
}

用户空间缓冲区:

以给文件写数据为例:

FileChannel fileChannel = new RandomAccessFile(new File("file-read-write.txt"), "rw").getChannel();
ByteBuffer  heapByteBuffer = ByteBuffer.allocate(4096);
fileChannel.write(heapByteBuffer);

sun.nio.ch.FileChannelImpl#write(java.nio.ByteBuffer)

在 IOUtil 中首先创建一个临时的 DirectByteBuffer,然后将 HeapByteBuffer 中的数据全部拷贝到这个临时的 DirectByteBuffer 中。这个 DirectByteBuffer 就是我们在 IO 系统调用中经常提到的用户空间缓冲区。

随后在 writeFromNativeBuffer 方法中通过  FileDispatcher 触发 JNI 层的 native 方法执行底层系统调用 write 。

而 JDK Buffer 也会根据其背后所依赖的虚拟内存在进程虚拟内存空间中具体所属的虚拟内存区域而演变出 HeapByteBuffer , MappedByteBuffer , DirectByteBuffer 。这三种不同类型 ByteBuffer 的本质区别就是其背后依赖的虚拟内存在 JVM 进程虚拟内存空间中的布局位置不同。

JVM 在操作系统的视角来看其实就是一个普通的进程,内核会根据进程在运行期间所需数据的功能特性不同,而为每一类数据专门开辟出一段虚拟内存区域出来。

位于 JVM 堆之外的内存其实都可以归属到 DirectByteBuffer 的范畴中。比如,位于 OS 堆之内,JVM 堆之外的 MetaSpace,即时编译(JIT) 之后的 codecache,JVM 线程栈,Native 线程栈,JNI 相关的内存,等等。 

JVM  在 OS 堆中划分出的 Direct Memory (上图红色部分)特指受到参数 -XX:MaxDirectMemorySize 限制的直接内存区域,比如通过 ByteBuffer#allocateDirect 申请到的 Direct Memory 容量就会受到该参数的限制。

而通过 Unsafe#allocateMemory 申请到的 Direct Memory 容量则不会受任何 JVM 参数的限制,只会受操作系统本身对进程所使用内存容量的限制。也就是说 Unsafe 类会脱离 JVM 直接向操作系统进行内存申请。

HeapByteBuffer 底层依赖的字节数组背后的内存位于 JVM 堆中:

MappedByteBuffer 背后所占用的内存位于 JVM 进程虚拟内存空间中的文件映射与匿名映射区中,系统调用 mmap 映射出来的内存就是在这个区域中划分的。

JDK 仅仅只是对 mmap 文件映射方式进行了封装,所以 MappedByteBuffer 的本质其实是对文件映射与匿名映射区中某一段虚拟映射区域在 JVM 层面上的描述。这段虚拟映射区的起始内存地址 addr 以及映射长度 length 被封装在 MappedByteBuffer 中的 address , capacity 属性中:

mmap:

mmap 有两种映射方式,一种是匿名映射,常用于进程动态的向 OS 申请内存,比如,glibc 库里提供的用于动态申请内存的 malloc 函数,当申请的内存大于 128K 的时候,malloc 就会调用 mmap 采用匿名映射的方式来申请。

另一种就是文件映射,用于将磁盘文件中的某段区域与进程虚拟内存空间中文件映射与匿名映射区里的某段虚拟内存区域进行关联映射。后续我们针对这段映射内存的读写就相当于是对磁盘文件的读写了,整个读写过程没有数据的拷贝,也没有切态的发生(这里特指在完成缺页处理之后)。

当我们调用 mmap 之后,OS 内核只是会为我们分配一段虚拟内存,然后将虚拟内存与磁盘文件进行映射,整个过程都只是在和虚拟内存打交道,并未出现任何物理内存的身影。而这段虚拟内存在 Java 层面就是 MappedByteBuffer。

由于现在我们只是刚刚完成了文件映射,仅仅只是在 JVM 层面得到了一个 MappedByteBuffer,这个 MappedByteBuffer 背后所依赖的虚拟内存就是我们通过 mmap 映射出来的。

此时我们还未对文件进行读写操作,所以该映射文件对应的 page cache 里还是空,没有任何文件页(用于存储文件数据的物理内存页)。而虚拟内存(MappedByteBuffer)与物理内存之间的关联是通过进程页表来完成的,由于此时内核还未对 MappedByteBuffer 分配物理内存,所以 MappedByteBuffer 在 JVM 进程页表中对应的页表项 PTE 还是空的。

当我们开始访问这段 MappedByteBuffer 的时候, CPU 会将 MappedByteBuffer 背后的虚拟内存地址送到 MMU 地址翻译单元中进行地址翻译查找其背后的物理内存地址。

如果 MMU 发现 MappedByteBuffer 在 JVM 进程页表中对应的页表项 PTE 还是空的,这说明 MappedByteBuffer 是刚刚被 mmap 系统调用映射出来的,还没有分配物理内存。

于是 MMU 就会产生缺页中断,随后 JVM  进程切入到内核态,进行缺页处理,为 MappedByteBuffer 分配物理内存。

内核在 do_fault 函数中处理 MappedByteBuffer 缺页的时候,首先会调用 find_get_page 从映射文件的 page cache 中尝试获取文件页,前面已经说了,当 MappedByteBuffer 刚刚被映射出来的时候,映射文件的 page cache 还是空的,没有缓存任何文件页,需要映射到内存的文件内容此时还静静地躺在磁盘上。

当文件页不在 page cache 中,内核则会调用 do_sync_mmap_readahead 来同步预读,这里首先会分配一个物理内存页出来,然后将新分配的内存页加入到 page cache 中,并增加页引用计数。

如果文件页已经缓存在 page cache 中了,则调用 do_async_mmap_readahead 启动异步预读机制,将相邻的若干文件页一起预读进 page cache 中。

随后会通过 address_space_operations (page cache 相关的操作函数集合)中定义的 readpage 激活块设备驱动从磁盘中读取映射的文件内容并填充到 page cache 里的文件页中。

经过 filemap_fault 函数的处理,此时 MappedByteBuffer 背后所映射的文件内容已经加载到 page cache 中了。

后续 JVM 进程在访问这段 MappedByteBuffer 的时候就相当于是直接访问映射文件的 page cache。整个过程是在用户态进行,不需要切态。

不需要切态说明:

后面 JVM  进程对 MappedByteBuffer 的读写就相当于是直接读写 page cache 了,关于这一点,很多读者朋友会有这样的疑问:page cache 是内核态的部分,为什么我们通过用户态的 MappedByteBuffer 就可以直接访问内核态的东西了?

这里大家不要被内核态这三个字给唬住了,虽然 page cache 是属于内核部分的,但其本质上还是一块普通的物理内存,想想我们是怎么访问内存的 ? 不就是先有一段虚拟内存,然后在申请一段物理内存,最后通过进程页表将虚拟内存和物理内存映射起来么,进程在访问虚拟内存的时候,通过页表找到其映射的物理内存地址,然后直接通过物理内存地址访问物理内存。

回到我们讨论的内容中,这段虚拟内存不就是 MappedByteBuffer 吗,物理内存就是 page cache 啊,在通过页表映射起来之后,进程在通过 MappedByteBuffer 访问 page cache 的过程就和访问普通内存的过程是一模一样的。

也正因为 MappedByteBuffer 背后映射的物理内存是内核空间的 page cache,所以它不会消耗任何用户空间的物理内存(JVM  的堆外内存),因此也不会受到 -XX:MaxDirectMemorySize 参数的限制

参考:从 Linux 内核角度探秘 JDK NIO 文件读写本质

从 Linux 内核角度探秘 JDK MappedByteBuffer

相关文章:

Java NIO Buffer概念

针对每一种基本类型的 Buffer &#xff0c;NIO 又根据 Buffer 背后的数据存储内存不同分为了&#xff1a;HeapBuffer&#xff0c;DirectBuffer&#xff0c;MappedBuffer。 HeapBuffer 顾名思义它背后的存储内存是在 JVM 堆中分配&#xff0c;在堆中分配一个数组用来存放 Buffe…...

Kubernetes在Java应用部署中的最佳实践

Kubernetes在Java应用部署中的最佳实践 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将探讨如何在Java应用程序中使用Kubernetes进行最佳部署实践。K…...

IOS Swift 从入门到精通:@escaping 和PreferenceKey

@escaping 在Swift中,@escaping是一个属性关键字,用于标记闭包参数。当一个闭包在函数返回之后才被调用时,这个闭包被称为逃逸闭包(Escaping Closure)。使用@escaping关键字可以告诉Swift编译器,传递给函数的闭包可能会在函数执行完毕后被调用,因此它需要“逃逸”函数的…...

基于PHP技术的校园论坛设计的设计与实现-计算机毕业设计源码08586

摘 要 本项目旨在基于PHP技术设计与实现一个校园论坛系统&#xff0c;以提供一个功能丰富、用户友好的交流平台。该论坛系统将包括用户注册与登录、帖子发布与回复、个人信息管理等基本功能&#xff0c;并结合社交化特点&#xff0c;增强用户之间的互动性。通过利用PHP语言及其…...

开机弹窗缺失OpenCL.dll如何解决?分享5种靠谱的解决方法

在电脑使用过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中之一就是“开机提示找不到OpenCL.dll”。那么&#xff0c;这个错误提示到底是怎么回事呢&#xff1f;它又对电脑有什么影响&#xff1f;我们又该如何解决这个问题并预防OpenCL.dll再次丢失呢&#xff1…...

IIS 服务器安装SSL证书

IIS 服务器安装SSL证书 步骤一&#xff1a;准备好 SSL 证书 准备好.pfx 格式的证书文件。 步骤二&#xff1a;安装 SSL 证书 1、打开【开始】菜单&#xff0c;找到【管理工具】&#xff0c;打开【Internet 信息服务&#xff08;IIS&#xff09;管理器】。 2、单击服务器名…...

二叉树第二期:堆的实现与应用

若对树与二叉树的相关概念&#xff0c;不太熟悉的同学&#xff0c;可移置上一期博客 链接&#xff1a;二叉树第一期&#xff1a;树与二叉树的概念-CSDN博客 本博客目标&#xff1a;对二叉树的顺序结构&#xff0c;进行深入且具体的讲解&#xff0c;同时学习二叉树顺序结构的应用…...

python-求出 e 的值

[题目描述] 利用公式 e11/1!1/2!1/3!⋯1/&#x1d45b;!&#xff0c;求 e 的值&#xff0c;要求保留小数点后 10 位。输入&#xff1a; 输入只有一行&#xff0c;该行包含一个整数 n&#xff0c;表示计算 e 时累加到1/n!。输出&#xff1a; 输出只有一行&#xff0c;该行包含计…...

模型微调方法

文章目录 LoRADoRAMoRA 以下部分参考自: https://mp.weixin.qq.com/s/OxYNpXcyHF57OShQC26n4g LoRA LoRA是微软于2021年推出的一种经济型微调模型参数的方法。 它在冻结大部分的模型参数的情况下&#xff0c;仅仅更新额外的部分参数。其性能与全参数微调相似。 LoRA假设微调期间…...

cesium使用cesium-navigation-es6插件创建指南针比例尺

cesium-navigation-es6 是一个为 Cesium.js 提供导航控件的库&#xff0c;它提供了一些常见的用户界面组件&#xff0c;用于在 Cesium 场景中实现用户导航和交互。下面将介绍如何在项目中使用 cesium-navigation-es6。 使用步骤 1. 安装 cesium-navigation-es6 首先&#xf…...

go sync包(七)Sync.Map

Sync.Map 原理 通过 read 和 dirty 两个字段实现数据的读写分离&#xff0c;读的数据存在只读字段 read 上&#xff0c;将最新写入的数据存在 dirty 字段上。读取时会先查询 read&#xff0c;不存在再查询 dirty&#xff0c;写入时则只写入 dirty。读取 read 并不需要加锁&am…...

Batch文件中的goto命令:控制流程的艺术

Batch文件&#xff0c;也称为批处理脚本&#xff0c;是Windows操作系统中用于自动化任务的一种脚本文件。在Batch脚本中&#xff0c;goto命令是一个至关重要的控制结构&#xff0c;它允许脚本跳转到指定的标签位置&#xff0c;从而实现循环、条件分支等复杂的控制流程。本文将详…...

【chatgpt】两层gcn提取最后一层节点输出特征,如何自定义简单数据集

文章目录 两层gcn&#xff0c;提取最后一层节点输出特征&#xff0c;10个节点&#xff0c;每个节点8个特征&#xff0c;连接关系随机生成&#xff08;无全连接层&#xff09;如何计算MSE 100个样本&#xff0c;并且使用批量大小为32进行训练第一个版本定义数据集出错&#xff0…...

Java面试题:讨论你如何保持对Java生态系统中新技术的了解

保持对Java生态系统中新技术的了解可以通过以下几种方法&#xff1a; 官方资源&#xff1a; Oracle的官方博客和新闻&#xff1a;Oracle是Java的主要维护者&#xff0c;其官方网站和博客会定期发布Java的新版本、功能更新和最佳实践。Java SE Documentation&#xff1a;Java官方…...

深度学习之Transformer模型的Vision Transformer(ViT)和Swin Transformer

Transformer 模型最初由 Vaswani 等人在 2017 年提出,是一种基于自注意力机制的深度学习模型。它在自然语言处理(NLP)领域取得了巨大成功,并且也逐渐被应用到计算机视觉任务中。以下是两种在计算机视觉领域中非常重要的 Transformer 模型:Vision Transformer(ViT)和 Swi…...

玩个游戏 找以下2个wordpress外贸主题的不同 你几找到几处

Aitken艾特肯wordpress外贸主题 适合中国产品出海的蓝色风格wordpress外贸主题&#xff0c;产品多图展示、可自定义显示产品详细参数。 https://www.jianzhanpress.com/?p7060 Ultra奥创工业装备公司wordpress主题 蓝色风格wordpress主题&#xff0c;适合装备制造、工业设备…...

React Native优质开源项目推荐与解析

目录 2. React Native的优势 2.1. 跨平台开发 2.2. 热更新 2.3. 丰富的社区资源 2.4. 优秀的性能 3. 优质开源项目推荐 3.1. React Navigation 3.1.1 项目简介 3.1.2 特点和优势 3.1.3 应用场景 3.2. Redux 3.2.1 项目简介 3.2.2 特点和优势 3.2.3 应用场景 3.3…...

树莓派安装windows系统

第1步&#xff1a; https://uupdump.net/下载对应的系统文件&#xff0c;所有选择项都默认选择。 第2步&#xff1a; 解压下载后的文件&#xff0c;双击运行下面文件。等待下载完成&#xff0c;等待过程很漫长&#xff0c;很考验耐心。 第3步&#xff1a; 提示已经finish了&…...

CSS-position/transform

1 需求 2 语法 在CSS中&#xff0c;positioning 和 transform 是两个非常重要的概念&#xff0c;它们分别用于控制元素在页面上的布局和变换。 Positioning CSS中的position属性用于设置元素的定位类型。它有几个值&#xff0c;包括&#xff1a; static&#xff1a;这是默认…...

面试题之一

路由的两种模式&#xff1a;hash模式和 history模式。 两种的区别、如何实现。 hash模式中#的作用 vue性能优化。具体如何实现&#xff08;回答了一个可以函数引入的方法引入路由。问&#xff09; keep-alive 说一下EventBus CSS&#xff1a; flex布局 css新特性 盒子模型 J…...

想转行AI行业?从入门到精通,掌握人工智能的核心技能!非常详细收藏我这一篇就够了

本文详细介绍了如何转行至算法岗&#xff0c;特别是机器视觉算法工程师的路径。文章首先分析了算法岗的要求&#xff0c;包括学历、项目经验、竞赛成绩等&#xff0c;并分享了个人的转行经历。接着&#xff0c;文章系统地梳理了所需的基础知识&#xff0c;如数学、编程语言、数…...

UnblockNeteaseMusic完整指南:如何一键解锁网易云音乐灰色歌曲

UnblockNeteaseMusic完整指南&#xff1a;如何一键解锁网易云音乐灰色歌曲 【免费下载链接】UnblockNeteaseMusic Revive unavailable songs for Netease Cloud Music 项目地址: https://gitcode.com/gh_mirrors/un/UnblockNeteaseMusic 还在为网易云音乐里那些灰色的、…...

干货合集:AI论文网站深度测评与推荐2026最新版

2026年真正好用的AI论文网站&#xff0c;核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测&#xff0c;千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队&#xff0c;覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…...

解决Ubuntu18.04网络共享中的常见问题:从Permission denied到外网访问失败

Ubuntu 18.04网络共享全攻略&#xff1a;从静态IP配置到外网访问故障排查 当你需要在两台Ubuntu 18.04设备间共享网络连接时&#xff0c;可能会遇到各种意料之外的障碍。无论是权限问题、静态IP配置错误还是NAT转发失效&#xff0c;每个环节都可能成为网络共享路上的绊脚石。本…...

从FAST_LIO到Livox HAP:ROS驱动版本升级中的消息适配实战

1. 当FAST_LIO遇上Livox HAP&#xff1a;问题诊断与场景分析 最近在实验室部署Livox HAP雷达时遇到了一个典型的技术断层问题&#xff1a;最新采购的HAP雷达只支持livox_ros_driver2驱动&#xff0c;而团队长期使用的FAST_LIO算法仍然依赖旧版livox_ros_driver。这就像给最新款…...

大文件传输不再难:探索高效文件分享工具的实战指南

大文件传输不再难&#xff1a;探索高效文件分享工具的实战指南 【免费下载链接】aliyunpan 阿里云盘命令行客户端&#xff0c;支持JavaScript插件&#xff0c;支持同步备份功能。 项目地址: https://gitcode.com/GitHub_Trending/ali/aliyunpan 你是否经历过这样的尴尬时…...

VTK三维模型导出实战:STL、OBJ与PLY格式的性能对比与应用场景解析

1. 三维模型导出格式概述 第一次接触三维模型导出时&#xff0c;我被各种文件格式搞得晕头转向。STL、OBJ、PLY这些格式到底有什么区别&#xff1f;为什么有的文件特别大&#xff0c;有的又特别小&#xff1f;经过几个项目的实战&#xff0c;我终于摸清了门道。三维模型导出本质…...

剪映视频去水印+去字幕+去logo三合一操作流程(新手必备)

在短视频创作热潮中&#xff0c;剪映凭借免费、易用的优势&#xff0c;成为多数创作者的首选剪辑工具。但在实际使用中&#xff0c;不少人会遇到一个共性问题&#xff1a;剪映导出的视频自带水印、素材中夹杂多余字幕&#xff0c;或搬运、引用的素材带有品牌Logo&#xff0c;尤…...

2026年SCI论文AI率5%以下怎么做到?这3款降AI工具帮你稳过顶刊

投了三篇SCI&#xff0c;AI率问题折腾了快半年。 第一次投稿时完全不知道期刊有AI率要求&#xff0c;论文被直接拒稿&#xff0c;编辑在邮件里特别说明了AI生成内容的问题。从那以后就开始认真研究这个。先说结论&#xff1a;嘎嘎降AI&#xff08;www.aigcleaner.com&#xff…...

M.2 (NGFF) PCIe 3.0 接口在嵌入式系统中的实战应用 —— 从硬件设计到驱动优化

1. M.2接口在嵌入式系统中的核心价值 第一次在嵌入式项目里用M.2接口时&#xff0c;我盯着那个比指甲盖大不了多少的插槽直犯嘀咕——这么小的玩意儿真能跑PCIe 3.0&#xff1f;实测后发现这简直是嵌入式系统的"万能扩展坞"。不同于消费级PC的M.2只用来插SSD&#x…...