堆外内存

前言

区别于 JVM 虚拟机提供的堆内内存,堆外内存不是由 JVM 管理,而是操作系统直接管理,分配内存空间于操作系统的用户态、JVM 虚拟机堆外的内存区域。

为什么需要堆外内存?

就像你做开发一样,总有标准接口无法解决的场景,需要一些个性化的方式进行处理。这里,堆外内存也是一样的道理。

堆外内存的一个核心目的是脱离JVM的内存管理,以便更灵活地支配内存空间。

堆外内存

堆外内存的优势

脱离JVM垃圾回收的管理

堆外内存不受 JVM 垃圾回收机制的管理,因此可以避免垃圾回收带来的停顿和性能波动。这对于需要稳定性能的应用程序(如高频交易系统)非常重要。

比如 Netty,设计的核心目标之一是提升性能和减少垃圾回收对应用程序的影响。因此 Netty 会在部分场景下使用 直接内存Direct Memory),即堆外内存,从而降低了垃圾回收的频率和停顿时间。

直接内存:

  • Netty 使用 ByteBuf 作为其数据缓冲区的抽象。ByteBuf 可以使用堆内存(Heap Memory)或直接内存(Direct Memory)。
  • 直接内存是在 JVM 堆之外分配的内存,减少了堆内存的使用,从而降低了垃圾回收的频率和停顿时间。
  • 使用直接内存可以提高 I/O 操作的性能,因为它避免了从堆内存到操作系统内核缓冲区的复制。

灵活的内存管理

开发者可以更灵活地管理内存的分配和释放,而不必依赖于JVM的垃圾回收。这对于需要精细控制内存使用的应用程序(如缓存系统)非常有用。

减少堆内存压力

使用堆外内存可以减少Java堆的使用,从而降低垃圾回收的频率和停顿时间。这对于需要处理大量数据的应用程序(如大数据处理、流媒体服务器等)非常有利。

提高I/O操作效率

堆外内存可以直接与操作系统的I/O操作交互,减少Java堆与内核缓冲区之间的中间复制步骤,从而提高I/O操作的效率。

为什么减少了复制操作?

1、传统Java堆内存的I/O操作

通常情况下,Java堆内存中的数据需要先复制到一个中间缓冲区(通常是内核缓冲区)才能进行I/O操作。这涉及从 Java堆内核缓冲区 的复制。

2、直接缓冲区的I/O操作

使用直接缓冲区时,数据可以直接从用户态的直接缓冲区传输到内核缓冲区。这减少了从Java堆到内核缓冲区的中间复制步骤。

直接缓冲区允许应用程序在用户态内存中准备数据,然后直接传输到内核态进行I/O操作。这种方式减少了 Java堆 与 内核缓冲区之间的复制。

操作系统也可以通过 DMA(直接内存访问)等技术进一步优化数据传输,减少 CPU 的参与。

堆外内存的缺点

复杂的内存管理:

使用堆外内存需要开发者手动管理内存的分配和释放,增加了内存泄漏的风险。

需要额外的代码来处理内存管理,增加了开发和维护的复杂性。 对编码者的要求更高

可能的性能开销:

虽然堆外内存可以提高 I/O 性能,但在某些情况下,访问堆外内存可能比访问堆内存更慢,因为它需要通过 JNI(Java Native Interface)进行访问。

调试困难:

内存泄漏和其他内存管理问题可能更难以调试,因为它们不在 JVM 的直接管理之下。

使用场景

大数据处理:

在处理大数据时,使用堆外内存可以避免频繁的垃圾回收,提高处理效率。

网络通信:

在高性能网络应用中,使用直接缓冲区可以提高数据传输效率。比如 Netty,利用直接内存,比如数据从 堆内 与用户态之间的相互拷贝,从而大大提升处理效率。

缓存系统:

一些缓存系统(如Apache Ignite)利用堆外内存来存储大量数据,以避免垃圾回收的影响。可以更加合理的控制缓存过期时间、缓存清理时间等。

小结

1、堆外内存是 JVM 堆外分配的内存空间,由操作系统管理,而不是 JVM

2、堆外内存空间也是属于操作系统的用户态空间

3、堆外内存可以使用更大、更加灵活的内存空间,提升 IO 数据传输效率;同时,对 GC 频次也可以更灵活的掌控。

4、堆外内存使用通常需要更加小心,因为它脱离了 JVM 管控,容易导致内存泄漏等无法及时清理。

虽然堆外内存本身仍然是用户态内存,但它通过减少Java堆与内核缓冲区之间的复制步骤,提高了I/O操作的效率。这种优化特别适用于高性能网络应用和需要频繁I/O操作的场景。

总的来说,堆外内存在需要高性能和低延迟的应用场景中非常有用,但也需要谨慎管理,以避免潜在的问题

相关推荐
方圆想当图灵5 分钟前
关于 Nacos 在 war 包部署应用关闭部分资源未释放的原因分析
后端
Lemon程序馆15 分钟前
今天聊聊 Mysql 的那些“锁”事!
后端·mysql
龙卷风040518 分钟前
使用本地IDEA连接服务器远程构建部署Docker服务
后端·docker
vv安的浅唱22 分钟前
Golang基础笔记七之指针,值类型和引用类型
后端·go
陪我一起学编程33 分钟前
MySQL创建普通用户并为其分配相关权限的操作步骤
开发语言·数据库·后端·mysql·oracle
Heo1 小时前
调用通义千问大模型实现流式对话
前端·javascript·后端
Java水解2 小时前
RabbitMQ用法的6种核心模式全面解析
后端·rabbitmq
用户4099322502122 小时前
FastAPI的查询白名单和安全沙箱机制如何确保你的API坚不可摧?
前端·后端·github