leak(二)netty java 11与监控
0 为什么usedDirectMemory不好用
PlatformDependent.usedDirectMemory始终返回-1
跟踪下来,io.netty.util.internal.PlatformDependent0#hasDirectBufferNoCleanerConstructor始终返回false
0.1
关于 mxbean
https://segmentfault.com/a/1190000044509636
因此netty所分配的直接内存大小,常规的监控手段无法监测,包括arthas、visualvm中的MBean、以及其他所有通过jmx获取直接内存数据的手段。mbean基于Bits,netty不基于
如果要监控,只能自定义实现,从PlatformDependent入手,网上已有不少资料。
0.2
关于 -XX:NativeMemoryTracking=detail
jcmd $pid VM.native_memory detail
懒得尝试
1
public static byte[] allocateUninitializedArray(int size) {
return UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD >= 0 && UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD <= size ? PlatformDependent0.allocateUninitializedArray(size) : new byte[size];
}
先关注到了这里,有没有可能后来用jvm内存得?
debug
发现UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD=-1,为什么:
UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD = javaVersion() >= 9 && PlatformDependent0.hasAllocateArrayMethod()?tryAllocateUninitializedArray:-1;
static boolean hasAllocateArrayMethod() {
return ALLOCATE_ARRAY_METHOD != null;
}
final Object maybeException1 = AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
try {
Class e = PlatformDependent0.getClassLoader(PlatformDependent0.class).loadClass("jdk.internal.misc.Unsafe");
Method method = e.getDeclaredMethod("getUnsafe", new Class[0]);
return method.invoke((Object)null, new Object[0]);
} catch (Throwable var3) {
return var3;
}
}
});
class io.netty.util.internal.PlatformDependent0$7 cannot access class jdk.internal.misc.Unsafe (in module java.base) because module java.base does not export jdk.internal.misc to unnamed module @6d3a9b8b
--add-opens java.base/jdk.internal.misc=ALL-UNNAMED --illegal-access=warn
增加-Dio.netty.uninitializedArrayAllocationThreshold=1,再debug
2
确实走后门那个方法了,而不是new byte[],但是还是没压跨掉
3 再回到io.netty.util.internal.PlatformDependent0#hasDirectBufferNoCleanerConstructor始终返回false,既然io.netty.util.internal.PlatformDependent#usedDirectMemory返回-1,就表示没有用直接内存?
试试看
io.netty.util.internal.PlatformDependent0#DIRECT_BUFFER_CONSTRUCTOR 这个为什么一直是null
java.lang.UnsupportedOperationException: Reflective setAccessible(true) disabled
报错,增加
-Dio.netty.tryReflectionSetAccessible=true
成功压垮(windows java11)
参考:
https://www.jianshu.com/p/c915aced3396
还是建议大家在使用jdk9以上的时候,把这个参数打开。
https://zhuanlan.zhihu.com/p/654366685
jdk17 下 netty 导致堆内存疯涨原因排查 | 京东云技术团队
netty 在 jdk 高版本需要手动添加 jvm 参数 -add-opens=java.base/java.nio=ALL-UNNAMED 和 - io.netty.tryReflectionSetAccessible 来开启采用直接调用底层 unsafe 来申请内存,如果不开启那么 netty 申请内存采用 ByteBuffer.allocateDirect 来申请直接内存,如果 EventLoop 消费任务申请的直接内存达到最大直接内存场景,那么就会导致有大量的任务消费都会同步去等待申请直接内存上。并且如果没有释放足够的直接内存,那么就会成为大面积的消费阻塞,也同时导致大量的对象累积在 netty 的无界队列 MpscUnboundedArrayQueue 中。
4 -Dio.netty.uninitializedArrayAllocationThreshold=100000
还是垮掉了
删除1中的两个config,一样
-XX:MaxDirectMemorySize=100k
-Dio.netty.tryReflectionSetAccessible=true
浙公网安备 33010602011771号