#java #netty
#java #netty
Вопрос:
Я вижу сбой JVM с фатальной ошибкой Netty 4.1.34 и Oracle Java 1.8.0_202 (обе последние версии) при выполнении некоторых (легких) нагрузочных тестов. К сожалению, сбой нелегко воспроизвести — кажется, это происходит только примерно в 1/10 случаев.
Это HTTP-прокси (который также поддерживает websocket), поэтому конвейеры Netty изначально настроены с соответствующими HTTP-кодерами / декодерами (HttpRequestDecoder, HttpResponseEncoder и т.д.), Но конвейеры будут изменены для поддержки декодеров / кодировщиков фреймов websocket, Если это применимо (например, когда видно рукопожатие ‘Upgrade: websocket’).
Изначально объекты ByteBuf в расширенном / пользовательском обработчике фрейма websocket не освобождались, что вызывало утечку памяти. Но после их выпуска я теперь вижу случайный сбой виртуальной машины Java:
--------------- T H R E A D ---------------
Current thread (0x00007f164807d000): JavaThread "nioEventLoopGroup-4-1" [_thread_in_Java, id=31262, stack(0x00007f163bc9d000,0x00007f163bd9e000)]
Stack: [0x00007f163bc9d000,0x00007f163bd9e000], sp=0x00007f163bd9b780, free space=1017k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V [libjvm.so 0xad33a5] VMError::report_and_die() 0x2e5
V [libjvm.so 0x4e0444] report_fatal(char const*, int, char const*) 0x54
V [libjvm.so 0x9cc815] SharedRuntime::continuation_for_implicit_exception(JavaThread*, unsigned char*, SharedRuntime::ImplicitExceptionKind) 0x345
V [libjvm.so 0x918eac] JVM_handle_linux_signal 0x6bc
V [libjvm.so 0x90b858] signalHandler(int, siginfo*, void*) 0x38
C [libpthread.so.0 0xf6d0]
J 4010 C2 io.netty.util.internal.PlatformDependent0.copyMemory(Ljava/lang/Object;JLjava/lang/Object;JJ)V (35 bytes) @ 0x00007f167ef0b3d2 [0x00007f167ef0b360 0x72]
J 3776 C1 io.netty.buffer.UnsafeByteBufUtil.setBytes(Lio/netty/buffer/AbstractByteBuf;JILio/netty/buffer/ByteBuf;II)V (134 bytes) @ 0x00007f167f65d27c [0x00007f167f65c5a0 0xcdc]
J 3635 C1 io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(ILio/netty/buffer/ByteBuf;II)Lio/netty/buffer/ByteBuf; (16 bytes) @ 0x00007f167f5aeb4c [0x00007f167f5aea40 0x10c]
J 3634 C1 io.netty.buffer.AbstractByteBuf.writeBytes(Lio/netty/buffer/ByteBuf;II)Lio/netty/buffer/ByteBuf; (30 bytes) @ 0x00007f167f5af0dc [0x00007f167f5aef00 0x1dc]
J 4007 C2 io.netty.channel.DefaultChannelPipeline$HeadContext.write(Lio/netty/channel/ChannelHandlerContext;Ljava/lang/Object;Lio/netty/channel/ChannelPromise;)V (12 bytes) @ 0x00007f167f6ca460 [0x00007f167f6ca2a0 0x1c0]
J 3999 C2 io.netty.channel.AbstractChannelHandlerContext$AbstractWriteTask.run()V (35 bytes) @ 0x00007f167f28d54c [0x00007f167f28d300 0x24c]
J 5000 C2 io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(J)Z (96 bytes) @ 0x00007f167f645b84 [0x00007f167f645600 0x584]
J 4688% C1 io.netty.channel.nio.NioEventLoop.run()V (236 bytes) @ 0x00007f167f0327f4 [0x00007f167f0317c0 0x1034]
j io.netty.util.concurrent.SingleThreadEventExecutor$5.run()V 44
j io.netty.util.concurrent.FastThreadLocalRunnable.run()V 4
j java.lang.Thread.run()V 11
v ~StubRoutines::call_stub
V [libjvm.so 0x68839b] JavaCalls::call_helper(JavaValue*, methodHandle*, JavaCallArguments*, Thread*) 0xddb
V [libjvm.so 0x685c63] JavaCalls::call_virtual(JavaValue*, KlassHandle, Symbol*, Symbol*, JavaCallArguments*, Thread*) 0x263
V [libjvm.so 0x686227] JavaCalls::call_virtual(JavaValue*, Handle, KlassHandle, Symbol*, Symbol*, Thread*) 0x47
V [libjvm.so 0x6f239c] thread_entry(JavaThread*, Thread*) 0x6c
V [libjvm.so 0xa7b9eb] JavaThread::thread_main_inner() 0xdb
V [libjvm.so 0xa7bcf1] JavaThread::run() 0x2d1
V [libjvm.so 0x90d8c2] java_start(Thread*) 0x102
C [libpthread.so.0 0x7e25]
Полный файл hs_err_pid*.log находится в Pastebin.
Выделите ли здесь что-нибудь очевидное, пожалуйста? Ранее я запускал устаревшую версию Netty, но обновление до последней версии не помогло (т. Е. мы по-прежнему получаем сбои).
Ответ №1:
Вероятно, вы сейчас слишком щедро освобождаете объекты ByteBuffer. Скорее всего, вызов PooledUnsafeDirectByteBuf.setBytes выполняет запись в освобожденную память, вызывая сбой.
Вот почему в Java есть сборка мусора, и с использованием буферов прямых байтов необходимо обращаться с осторожностью.
Комментарии:
1. Спасибо, вы абсолютно правы. Я выпускал 2 объекта ByteBuf в этой области, один из которых был правильным для выполнения, а другой — нет.