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

Java的直接内存(Direct Memory)是什么意思?

直接内存:

直接内存(Direct Memory) 指的是 JVM 之外直接向操作系统申请的一块内存区域。它不受 JVM 堆(Heap)大小的限制,而是由操作系统的 本机内存(Native Memory) 管理。


1. 为什么需要直接内存?

直接内存的主要目的是提高 I/O 读写性能,因为它可以绕过 Java 堆,直接和操作系统交互,减少数据在 JVM 内部的复制次数。

在 Java 里面,所有数据最终都需要从内存到 CPU 处理,而 Java 传统的堆内存操作涉及多次复制:

  • Java 堆JVM 本地方法操作系统内核缓冲区磁盘或网络
  • 传统方式下,每次 I/O 操作,数据必须从堆复制到本地缓冲区,然后再写入操作系统,这会影响性能。

直接内存的优势: ✅ 减少数据拷贝,提升 I/O 速度
避免 GC 干扰(垃圾回收不会管理直接内存)

常见的使用场景

  • NIO(New IO):Java NIO 提供的 ByteBuffer.allocateDirect() 允许分配直接内存,避免 I/O 复制。
  • Netty:高性能网络框架 Netty 也大量使用直接内存来优化网络通信。
  • 数据库驱动(如 MySQL JDBC Driver):某些数据库驱动(如 MySQL Connector)会使用直接内存加速数据传输。

2. 直接内存的分配

直接内存不受 Java 堆的 -Xmx 限制,但受 操作系统总内存-XX:MaxDirectMemorySize 限制。

(1) 使用 ByteBuffer.allocateDirect() 申请直接内存

import java.nio.ByteBuffer;

public class DirectMemoryDemo {
    public static void main(String[] args) {
        // 申请 100MB 直接内存
        ByteBuffer buffer = ByteBuffer.allocateDirect(100 * 1024 * 1024);
        System.out.println("直接内存分配成功!");
    }
}

解释

  • ByteBuffer.allocateDirect(size) 会在堆外申请 size 大小的内存。
  • 直接内存不会受 GC 影响,但需要手动释放(否则可能 OOM)。

3. 直接内存的限制

虽然直接内存有优势,但也有一些缺点和限制

(1) 受 -XX:MaxDirectMemorySize 限制

JVM 参数 -XX:MaxDirectMemorySize 控制最大直接内存大小,例如:

java -XX:MaxDirectMemorySize=512M DirectMemoryDemo

如果分配的直接内存超过限制,会抛出 OutOfMemoryError: Direct buffer memory

(2) 不能被 GC 直接回收

直接内存不会受到 Java GC 的管理,因此:

  • 如果程序没有释放直接内存,会造成内存泄漏。
  • GC 只会在 ByteBuffer 对象被回收时,尝试释放直接内存,但释放时间不可控。

(3) 需要手动释放

  • Java NIO 的 ByteBuffer.allocateDirect() 申请的直接内存是由 Cleaner 进行回收的,但不会立即释放。
  • 可以用反射调用 Cleaner.clean() 方法手动释放
import sun.misc.Cleaner;
import java.nio.ByteBuffer;
import java.lang.reflect.Method;

public class DirectMemoryClean {
    public static void main(String[] args) throws Exception {
        ByteBuffer buffer = ByteBuffer.allocateDirect(100 * 1024 * 1024);
        System.out.println("直接内存分配成功!");

        // 释放直接内存
        Method cleanerMethod = buffer.getClass().getMethod("cleaner");
        cleanerMethod.setAccessible(true);
        Cleaner cleaner = (Cleaner) cleanerMethod.invoke(buffer);
        cleaner.clean();

        System.out.println("直接内存已释放!");
    }
}

由于 Cleaner 需要 sun.misc 包,Java 9+ 之后推荐使用 Unsafe 或者 Netty 的 PlatformDependent.freeDirectBuffer() 进行释放


4. 直接内存 vs Java 堆内存

对比项直接内存(Direct Memory)堆内存(Heap Memory)
存储位置JVM 之外,操作系统内存JVM 内部,由 GC 管理
访问速度快,直接与 OS 交互较慢,需要数据拷贝
GC 管理不受 GC 影响,需手动释放受 GC 影响,自动管理
I/O 操作适合高频 I/O 操作适合普通对象存储
适用场景NIO、Netty、数据库驱动普通 Java 对象管理

5. 总结

  1. 直接内存JVM 之外的内存区域,适用于高性能 I/O 操作(如 Netty、NIO)。
  2. 它不会受到 GC 影响,但需要手动释放,否则可能导致 OOM。
  3. JVM 参数 -XX:MaxDirectMemorySize 控制直接内存上限,默认值与堆大小一致。
  4. 适用于 I/O 密集型场景,如网络通信(Netty)、数据库驱动、文件操作等

如果你的系统需要高性能 I/O,可以考虑使用直接内存优化性能


http://www.kler.cn/a/542393.html

相关文章:

  • 【编程实践】vscode+pyside6环境部署
  • 交叉编译工具链下载和使用
  • 1312:【例3.4】昆虫繁殖
  • Linux磁盘空间使用率100%(解决删除文件后还是显示100%)
  • 方舟字节码原理剖析:架构、特性与实践应用
  • 没用的文章又➕1
  • 计算机毕业设计Spark+大模型知网文献论文推荐系统 知识图谱 知网爬虫 知网数据分析 知网大数据 知网可视化 预测系统 大数据毕业设计 机器学习
  • 工具-screen-管理终端会话(服务器长时间运行任务)
  • Redis存储⑥Redis五大数据类型之 Zset
  • MFC线程安全案例
  • 对JVM的错误理解与纠正
  • 解决虚幻Unreal Engine手动配置安卓打包环境后无法识别SDK问题
  • Express 中间件
  • VUE3项目结构说明
  • android studio开发科大讯飞最新版
  • 深入理解x86汇编:GNU格式的全面指南
  • 深入理解Java对接DeepSeek
  • 如何在WPF中实现软件内嵌效果
  • Baklib使数字化内容管理更加高效和便捷设计理念和实用案例解析
  • Linux 系统使用教程
  • 使用epoll与sqlite3进行注册登录
  • 基于ESP32的远程开关灯控制(ESP32+舵机+Android+物联网云平台)——下
  • linux部署nacos集群
  • 【Elasticsearch】derivative聚合
  • CSS 属性选择器详解与实战示例
  • 认识Electron 开启新的探索世界一