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

懒得尝试 

 

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

 

确实走后门那个方法了,而不是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

posted on 2024-04-15 15:37  silyvin  阅读(174)  评论(0)    收藏  举报