讲师中心 微信公众号
AI工具推荐 视频效率加速

什么是Java中的直接内存(Direct Memory)_零拷贝技术与堆外存储

夜伟同学_1495

夜伟同学_1495

发布时间:2026-02-16 08:27:09

|

881人浏览过

|

来源于php中文网

原创

DirectByteBuffer 通过 Unsafe.allocateMemory() 或 allocateDirect() 在堆外分配内存,对象在堆中而数据在直接内存,依赖 Cleaner 异步释放,不显式清理易致泄漏;零拷贝需 DirectByteBuffer 提供地址指针,HeapByteBuffer 会退化为用户态拷贝;定位泄漏需 NMT、jcmd、jstack 结合分析;Netty 池化复用有线程绑定与 retain/release 匹配要求。

什么是java中的直接内存(direct memory)_零拷贝技术与堆外存储

DirectByteBuffer 是怎么分配的

Java 里的直接内存不是 new 出来的,也不是 GC 管的堆内存。它靠 Unsafe.allocateMemory() 或 ByteBuffer.allocateDirect() 触发本地调用,在堆外申请物理内存。

常见错误现象:OutOfMemoryError: Direct buffer memory —— 这和堆内存溢出无关,是 JVM 直接内存限额被突破了(默认通常 64MB,由 -XX:MaxDirectMemorySize 控制)。

  • ByteBuffer.allocateDirect(1024) 返回的是 DirectByteBuffer 实例,对象本身在堆上,但背后那块 1KB 内存不在堆里
  • 不显式调用 cleaner(比如通过反射强制触发),这块内存不会随 GC 自动释放,依赖 JVM 的 Cleaner 机制异步回收,有延迟
  • 频繁创建/丢弃大块 DirectByteBuffer 容易导致直接内存碎片,尤其在长期运行服务中,表现为内存占用持续上涨但没明显泄漏点

零拷贝为什么非要走 DirectBuffer

零拷贝(如 FileChannel.transferTo())要求数据源/目标至少有一方是直接内存,否则内核无法绕过 JVM 堆做 DMA 传输。

使用场景:NIO 网络传输、大文件 sendfile、Netty 的 PooledByteBufAllocator 默认优先分配 DirectByteBuffer。

立即学习“Java免费学习笔记(深入)”;

Java调试
Java调试

通过 JDWP 实现 Java 远程调试:连接远程 JVM、设置断点、单步执行代码、查看变量值、获取调用栈。适用于需要调试远程 Java 应用、排查运行时状态、追踪代码执行流程的场景。 术语注解 JDWP:Java Debug Wire Protocol,Java 调试有线协议(Java 远程调试底层通信协议) remote JVM:远程 Java 虚拟机 step through code:代码单步调试(步入 / 步过 / 步出调试) inspect variables:变量查看 / 变量检视 stac

下载
  • 如果传入的是堆内 HeapByteBuffer,transferTo() 会退化成“用户态拷贝 + 系统调用”,多一次 memcpy,吞吐掉一截
  • FileChannel.map() 返回的 MappedByteBuffer 也是直接内存,但它映射的是文件页,生命周期与文件句柄强绑定,unmap() 在 Java 里没有公开 API,靠 GC 触发,容易卡住文件删除
  • Linux 下 sendfile() 和 splice() 对 buffer 类型有硬性要求;JVM 层面只对 DirectByteBuffer 暴露了地址指针(address 字段),这是零拷贝能成立的底层前提

堆外内存泄漏怎么定位

堆外泄漏不像堆内存那样能用 jmap/jhat 直接看,得靠组合手段交叉验证。

常见错误现象:JVM 堆内存稳定,但进程 RSS 持续上涨;jstat -gc 显示 CCST(Concurrent Cycle Time)异常高;Native Memory Tracking (NMT) 报告 Internal 或 Other 分类暴涨。

  • 启动时加 -XX:NativeMemoryTracking=detail,运行中用 jcmd <pid> VM.native_memory summary</pid> 查直接内存总量
  • 对比 java.lang.management.MemoryUsage.getMax()(堆上限)和 sun.misc.VM.maxDirectMemory()(直接内存上限),确认是否真超限
  • 用 jstack 看是否有大量 Cleaner 线程阻塞在 Unsafe.freeMemory(),说明释放路径被某些 native 资源(如未关闭的 FileChannel)拖住

Netty 里 PooledDirectByteBuf 的坑

Netty 的池化 DirectByteBuf 能复用内存,但复用逻辑藏在 Recycler 里,和使用者预期常有偏差。

性能影响:池化减少 malloc/free 开销,但若线程间误传 ByteBuf(比如从 IO 线程传到业务线程再还回去),会导致缓存行失效、跨 NUMA 访问变慢。

  • 调用 buf.release() 不等于内存立刻归还池子,而是先进 Recycler.Stack 的本地队列,等下次同线程申请时才复用
  • 如果 buf 被 retain 了多次,只 release 一次不会真正归还,容易造成“假泄漏”——NMT 显示已分配内存不降,但实际只是被 retain 锁住了
  • Unpooled.directBuffer() 每次都 new 新的 DirectByteBuffer,适合短生命周期、不可池化场景(如协议头解析),别误当“轻量版”用

直接内存不是银弹,它把 GC 压力换成了更难调试的 native 资源管理问题。最常被忽略的是:你写的 release() 是否真的被执行到了,还是被异常吞掉、被线程中断跳过、或者压根没写。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

火山引擎

火山引擎是一款面向企业的云计算与AI服务平台。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

相关专题

更多
Java I/O 与 NIO 编程体系合集
Java I/O 与 NIO 编程体系合集

全面讲解 Java I/O 编程的演进与核心 API,涵盖传统 I/O 的字节流(InputStream/OutputStream)与字符流(Reader/Writer)体系、装饰器模式在 I/O 中的应用(BufferedReader/InputStreamReader)、文件读写与目录操作、NIO 核心三要素(Buffer 缓冲区/Channel 通道/Selector 选择器)、ByteBuffer 操作与内存映射文件(Mappe

492

2026.04.29

Java I/O 与 NIO 编程体系合集
Java I/O 与 NIO 编程体系合集

全面讲解 Java I/O 编程的演进与核心 API,涵盖传统 I/O 的字节流(InputStream/OutputStream)与字符流(Reader/Writer)体系、装饰器模式在 I/O 中的应用(BufferedReader/InputStreamReader)、文件读写与目录操作、NIO 核心三要素(Buffer 缓冲区/Channel 通道/Selector 选择器)、ByteBuffer 操作与内存映射文件(Mappe

492

2026.04.29

C++ 智能指针与现代内存管理
C++ 智能指针与现代内存管理

深入讲解 C++ 现代内存管理的核心工具——智能指针,涵盖 unique_ptr 独占所有权语义、shared_ptr 引用计数机制与循环引用问题、weak_ptr 弱引用的应用场景、make_unique/make_shared 工厂函数的性能优势、自定义删除器的编写、RAII 资源管理思想的实践,以及从裸指针迁移到智能指针的重构策略,帮助开发者编写安全无泄漏的现代 C++ 代码。

379

2026.04.23

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

6707

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2788

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

6707

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2788

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

4698

2023.08.10

Postman身份认证怎么配置
Postman身份认证怎么配置

本专题从实际API接口调试场景出发,讲解Postman身份认证的完整配置流程,包括常见认证协议介绍、授权参数设置、访问令牌填写、OAuth 2.0授权及认证失败排查,帮助用户正确完成接口授权与访问验证。

0

2026.11.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn