GRP C Серьезная утечка памяти с Netty - PullRequest
0 голосов
/ 21 апреля 2020

Иногда я получаю исключение на GRP C с использованием netty.

Я создаю группу серверов примерно так:

        for(int i = 0; i < 4; i++) {
            var executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(1);
            var eventGroup = new NioEventLoopGroup(1); //One thread for each channel
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
            _channels[i] = NettyChannelBuilder
                    .forAddress(host, port + i)
                    .executor(executor)
                    .channelType(NioSocketChannel.class)
                    .eventLoopGroup(eventGroup)
                    .usePlaintext()
                    .build();
            var stub = ServiceDPASGrpc.newStub(_channels[i]);
            _stubs[i] = stub;
            _executors[i] = executor;
        }
        for (int i = 0; i < 4; i++) {
            var impl = ...
            _servers[i] = NettyServerBuilder.forPort(port + i).addService(impl).build();
            _servers[i].start();
            _impls[i] = impl;

        }

в конце приложения я закрываю все так:

        for (int i = 0; i < 4; i++) {
            _channels[i].shutdown();
            _executors[i].shutdown();
            _servers[i].shutdown();

        }

Однако иногда я получаю исключение, заявляющее:

Apr 21, 2020 2:32:51 PM io.grpc.netty.shaded.io.netty.util.ResourceLeakDetector reportTracedLeak
SEVERE: LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records: 
Created at:
        io.grpc.netty.shaded.io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:349)
        io.grpc.netty.shaded.io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:187)
        io.grpc.netty.shaded.io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:178)
        io.grpc.netty.shaded.io.netty.buffer.AbstractByteBufAllocator.ioBuffer(AbstractByteBufAllocator.java:139)
        io.grpc.netty.shaded.io.netty.channel.DefaultMaxMessagesRecvByteBufAllocator$MaxMessageHandle.allocate(DefaultMaxMessagesRecvByteBufAllocator.java:114)
        io.grpc.netty.shaded.io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:147)
        io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
        io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
        io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
        io.grpc.netty.shaded.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
        io.grpc.netty.shaded.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        io.grpc.netty.shaded.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        io.grpc.netty.shaded.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        java.base/java.lang.Thread.run(Thread.java:834)

что я делаю не так

1 Ответ

0 голосов
/ 21 апреля 2020

несколько вещей для проверки.

  1. вам не нужно создавать EventL oop размера 1 в каждом l oop. каждый канал использует только 1 EventL oop из EventLoopGroup. Таким образом, вы можете просто передать в EventLoopGroup большее количество потоков (если оно меньше, чем число каналов, которыми является общий поток).

  2. отключение канала не является операцией блокировки. в фоновом режиме, это все еще нужно немного поработать, чтобы завершить et c. вам нужно подождать, чтобы корректно завершить работу.

_channels[i]
  .shutdown() // could use `shutdownNow`, but still need to wait
  .awaitTermination(5, TimeUnit.SECONDS); // or whatever time
...