前言
最近在 记一次 netty 内存泄露 中有还有一些问题
比如 java.nio.ByteBuffer 中分配空间的时候, 直接内存 受限于 Bits.maxMemory
在 netty 中的 PlatformDependent 中分配空间的时候, 直接内存 受限于 PlatformDependent.DIRECT_MEMORY_LIMIT
然后 这两个 maxMemory 均是来自于 VM.maxDirectMemory, 那么 这个 VM.maxDirectMemory 又是怎么来的呢?
这个问题之所以要探究一下, 是因为我之前配置 MaxDirectMemorySize 似乎是不生效 还是怎么的?, 但是 今天试了一下 又可以了
以下代码截图基于 jdk8
调试不到的代码?
来看一下 VM.maxDirectMemory, 取自于 属性 directMemory
然后 我们看一下 这个字段初始化的地方
- 它是有一个默认值
- 是 VM.saveAndRemoveProperties 里面的初始化代码
然后 我们打上断点查看, 发现 初始化部分的代码 这里居然断点停不了? 这是一个很神奇的事情
但是 获取 maxMemorty 的时候, maxMemory 已经是一个正常的我们期望的数值了
但是 它是在哪里初始化的? 难道还有其他地方 ?
基于 HotspotVM 的调试
呵呵 java 层面看不到什么情况, 只能来 vm 调试一下了
可以看到 System.initPhase1 里面某一个步骤调用了 Runtime.maxMemory
System.initPhase1 是 jdk9 中的初始化方法, 对应于 jdk8 是 System.initializeSystemClass
输出一下当前线程的堆栈信息
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 里面初始化的
另外我们看一下 默认值, 取自 Runtime.maxMemorty
Runtime.maxMemorty 的实现是取自 堆空间的大小
为什么 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 相关服务尚未暴露, 因此是 客户端是感知不到的
如何配置 VM.maxDirectMemory ?
从上面 VM 的代码里面我们可以看到 读取的配置是 sun.nio.MaxDirectMemorySize
那么可以直接配置 sun.nio.MaxDirectMemorySize 嘛? 答案是否定的
VM.saveAndRemoveProperties 传入的 properties 来自于这里
-
Arguments::system_properties 里面是没有 “sun.nio.MaxDirectMemorySize” 属性的
-
另外 下面有一段关于 sun.nio.MaxDirectMemorySize 和 MaxDirectMemorySize 的特殊处理, 检查是否有 MaxDirectMemorySize 参数, 如果没有, 设置 sun.nio.MaxDirectMemorySize 为 -1, 否则 设置 MaxDirectMemorySize 的值到 sun.nio.MaxDirectMemorySize
本地内存使用可以超过 VM.maxMemorty 配置的吗?
这个答案是 肯定的
不管是 java.nio.DirectBuffer 分配空间, 还是 PlatformDependent 分配空间
对于 maxMemorty 的限制都是逻辑上的限制
如果 我设置 MaxDirectMemorySize 为 32M, java.nio.DirectBuffer 分配 29M, PlatformDependent 分配 29M, 也是可以的
呵呵 算是 tricks 吧
完
参考
记一次 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/
转载文章受原作者版权保护。转载请注明原作者出处!