47 VM.maxDirectMemory() 来自于哪里

前言

最近在 记一次 netty 内存泄露 中有还有一些问题

比如 java.nio.ByteBuffer 中分配空间的时候, 直接内存 受限于 Bits.maxMemory

在 netty 中的 PlatformDependent 中分配空间的时候, 直接内存 受限于 PlatformDependent.DIRECT_MEMORY_LIMIT

然后 这两个 maxMemory 均是来自于 VM.maxDirectMemory, 那么 这个 VM.maxDirectMemory 又是怎么来的呢?

这个问题之所以要探究一下, 是因为我之前配置 MaxDirectMemorySize 似乎是不生效 还是怎么的?, 但是 今天试了一下 又可以了

以下代码截图基于 jdk8

调试不到的代码?

来看一下 VM.maxDirectMemory, 取自于 属性 directMemory

47 VM.maxDirectMemory() 来自于哪里

然后 我们看一下 这个字段初始化的地方

  1. 它是有一个默认值

47 VM.maxDirectMemory() 来自于哪里
  1. 是 VM.saveAndRemoveProperties 里面的初始化代码

47 VM.maxDirectMemory() 来自于哪里

然后 我们打上断点查看, 发现 初始化部分的代码 这里居然断点停不了? 这是一个很神奇的事情

但是 获取 maxMemorty 的时候, maxMemory 已经是一个正常的我们期望的数值了

但是 它是在哪里初始化的? 难道还有其他地方 ?

47 VM.maxDirectMemory() 来自于哪里

基于 HotspotVM 的调试

呵呵 java 层面看不到什么情况, 只能来 vm 调试一下了

可以看到 System.initPhase1 里面某一个步骤调用了 Runtime.maxMemory

System.initPhase1 是 jdk9 中的初始化方法, 对应于 jdk8 是 System.initializeSystemClass

47 VM.maxDirectMemory() 来自于哪里

输出一下当前线程的堆栈信息

    at java.lang.Runtime.maxMemory(java.base/Native Method)
    at jdk.internal.misc.VM.saveAndRemoveProperties(java.base/VM.java:190)
    at java.lang.System.initPhase1(java.base/System.java:1949)

jdk 的 VM 里面 190 行对应于初始化 directMemory, 这个就证明了 上面我们不确定的东西

VM.maxMemorty 的初始化确实是在 VM.saveAndRemoveProperties 里面初始化的

47 VM.maxDirectMemory() 来自于哪里

另外我们看一下 默认值, 取自 Runtime.maxMemorty

Runtime.maxMemorty 的实现是取自 堆空间的大小

47 VM.maxDirectMemory() 来自于哪里

为什么 VM.saveAndRemoveProperties 调试不到?

调试的文章, 可以参考 调试启动 suspend=y 的情况下, jps 得到 — main class information unavailable

我们看一下 jvmti 暴露 jdwp 服务初始化的地方, 这里 bagEnumrateOver 是 bind 端口, 接受 jdwp 服务的地方

仔细看 这里是在 Threads::create_vm 3800 行的地方, 而上面调用 System.initPhase1/initializeSystemClass 是在 Threads::create_vm 3700 行的地方

此时 jdwp 相关服务尚未暴露, 因此是 客户端是感知不到的

47 VM.maxDirectMemory() 来自于哪里

如何配置 VM.maxDirectMemory ?

从上面 VM 的代码里面我们可以看到 读取的配置是 sun.nio.MaxDirectMemorySize

那么可以直接配置 sun.nio.MaxDirectMemorySize 嘛? 答案是否定的

VM.saveAndRemoveProperties 传入的 properties 来自于这里

  1. Arguments::system_properties 里面是没有 “sun.nio.MaxDirectMemorySize” 属性的

  2. 另外 下面有一段关于 sun.nio.MaxDirectMemorySize 和 MaxDirectMemorySize 的特殊处理, 检查是否有 MaxDirectMemorySize 参数, 如果没有, 设置 sun.nio.MaxDirectMemorySize 为 -1, 否则 设置 MaxDirectMemorySize 的值到 sun.nio.MaxDirectMemorySize

47 VM.maxDirectMemory() 来自于哪里

本地内存使用可以超过 VM.maxMemorty 配置的吗?

这个答案是 肯定的

不管是 java.nio.DirectBuffer 分配空间, 还是 PlatformDependent 分配空间

对于 maxMemorty 的限制都是逻辑上的限制

如果 我设置 MaxDirectMemorySize 为 32M, java.nio.DirectBuffer 分配 29M, PlatformDependent 分配 29M, 也是可以的

呵呵 算是 tricks 吧

47 VM.maxDirectMemory() 来自于哪里

参考

记一次 netty 内存泄露 调试启动 suspend=y 的情况下, jps 得到 — main class information unavailable

Original: https://blog.csdn.net/u011039332/article/details/121722084
Author: 蓝风9
Title: 47 VM.maxDirectMemory() 来自于哪里

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/652829/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球