堆外内存

前言

区别于 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操作的场景。

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

相关推荐
考虑考虑7 分钟前
使用jpa中的group by返回一个数组对象
spring boot·后端·spring
GiraKoo15 分钟前
【GiraKoo】C++11的新特性
c++·后端
MO2T20 分钟前
使用 Flask 构建基于 Dify 的企业资金投向与客户分类评估系统
后端·python·语言模型·flask
光溯星河28 分钟前
【实践手记】Git重写已提交代码历史信息
后端·github
PetterHillWater1 小时前
Trae中实现OOP原则工程重构
后端·aigc
圆滚滚肉肉1 小时前
后端MVC(控制器与动作方法的关系)
后端·c#·asp.net·mvc
SimonKing1 小时前
拯救大文件上传:一文彻底彻底搞懂秒传、断点续传以及分片上传
java·后端·架构
深栈解码1 小时前
JUC并发编程 内存布局和对象头
java·后端
37手游后端团队1 小时前
巧妙利用装饰器模式给WebSocket连接新增持久化
后端
编程乐趣1 小时前
C#版本LINQ增强开源库
后端