直接内存与 JVM 源码分析

本文深入探讨直接内存(堆外内存),包括其概念、使用场景、优缺点以及内存泄漏案例。通过分析,揭示直接内存如何通过 Unsafe、Netty 和 JNI/JNA 申请。讲解了为何使用直接内存以提高性能,同时指出其管理难度和潜在风险。文章还涉及如何使用 NMT 工具排查直接内存泄漏问题,并通过 JVM 源码分析了直接内存的默认大小和分配机制,最后给出了案例分析及解决 OOM 问题的方法。
摘要由CSDN通过智能技术生成

直接内存与 JVM 源码分析

直接内存(堆外内存)

在这里插入图片描述
直接内存有一种叫法,堆外内存。

直接内存(堆外内存)指的是 Java 应用程序通过直接方式从操作系统中申请的内存。这个差别与之前的堆、栈、方法区,那些内存都是经过了虚拟化。所 以严格来说,这里是指直接内存。

直接内存有哪些?

 使用了 Java 的 Unsafe 类,做了一些本地内存的操作;
 Netty 的直接内存(Direct Memory),底层会调用操作系统的 malloc 函数。
 JNI 或者 JNA 程序,直接操纵了本地内存,比如一些加密库;

JNI 是 Java Native Interface 的缩写,通过使用 Java 本地接口书写程序,可以确保代码在不同的平台上方便移植。

JNA(Java Native Access )提供一组 Java 工具类用于在运行期间动态访问系统本地库(native library:如 Window 的 dll)而不需要编写任何 Native/JNI 代码。 开发人员只要在一个 java 接口中描述目标 native library 的函数与结构,JNA 将自动实现 Java 接口到 native function 的映射。

JNA 是建立在 JNI 技术基础之上的一个 Java 类库,它使您可以方便地使用 java 直接访问动态链接库中的函数。

原来使用 JNI,你必须手工用 C 写一个动态链接库,在 C 语言中映射 Java 的数据类型。

JNA 中,它提供了一个动态的 C 语言编写的转发器,可以自动实现 Java 和 C 的数据类型映射,你不再需要编写 C 动态链接库。

也许这也意味着,使用 JNA 技术比使用 JNI 技术调用动态链接库会有些微的性能损失。但总体影响不大,因为 JNA 也避免了 JNI 的一些平台配置的开销。

代码案例

1、 Unsafe 类,-XX:MaxDirectMemorySize 参数的大小限制对这种是无效的在这里插入图片描述
2、ByteBuffer 的这种方式,受到 MaxDirectMemorySize 参数的大小限制 其实底层是在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

为什么要使用直接内存

直接内存,其实就是不受 JVM 控制的内存。相比于堆内存有几个优势:
1、减少了垃圾回收的工作,因为垃圾回收会暂停其他的工作。
2、加快了复制的速度。因为堆内在 flush 到远程时,会先复制到直接内存(非堆内存),然后再发送,而堆外内存相当于省略掉了这个工作。
3、可以在进程间共享,减少 JVM 间的对象复制,使得 JVM 的分割部署更容易实现。
4、可以扩展至更大的内存空间。比如超过 1TB 甚至比主存还大的空间。

直接内存的另一面

直接内存有很多好处,我们还是应该要了解它的缺点:
1、 堆外内存难以控制,如果内存泄漏,那么很难排查
2、 堆外内存相对来说,不适合存储很复杂的对象。一般简单的对象比较适合。

直接内存案例和场景分析

内存泄漏案例

工作中经常会使用 Java 的 Zip 函数进行压缩和解压,这种操作在一些对传输性能较高的的场景经常会用到。

程序将会申请 1kb 的随机字符串,然后不停解压。为了避免让操作系统陷入假死状态,我们每次都会判断操作系统内存使用率,在达到 60% 的时候, 我们将挂起程序(不在解压,只不断的让线程休眠)

通过访问 8888 端口,将会把内存阈值提高到 85%。

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值