泄漏:ByteBuf.release()在被垃圾收集之前没有被调用

时间:2014-05-08 11:00:14

标签: java networking netty

这是我的服务器端代码。此代码在netty的帮助下读取udp流量。但是,有时候我有一个错误....我无法解决它......这是非常悲伤......

@Override
     protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
      ByteBuf bb = msg.content();
      RoomController roomController = RoomController.getInstance();
      try
      {
       int opcode = bb.readUnsignedByte();
       byte slot = bb.readByte();
       byte[] ignore = new byte[8];
       bb.readBytes(ignore);
       int accountId = bb.readUnsignedByte();
       switch(opcode)
        {
         case 65: {
          log.info("Try connect player " + msg.sender().getAddress() + ":" + msg.sender().getPort());
          Player player = roomController.getPlayer(msg.sender().getAddress());
          if(player != null) {
           ByteBuffer _buffer = new ByteBuffer();
           _buffer.writeC((byte) 66);
           _buffer.writeC((byte) 0);
           _buffer.writeB(new byte[5]);
           _buffer.writeC((byte) 0x0b);
           _buffer.writeB(new byte[3]);
           player.playerPort = msg.sender().getPort();
           log.info("Send accept data! " + msg.sender().getAddress().toString() + ":" + msg.sender().getPort());
           ctx.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(_buffer.getData(), 0, _buffer.getData().length), msg.sender()));
          }
          break;
         }
         //case (byte) 131:
         //case (byte) 132:
         //case 84:
         //case 97:
         case 131:
         case 132:
         case 4:
         case 3: {
          Player player = roomController.getPlayer(msg.sender().getAddress());
          if(player != null) {
           if(player.isActive) {
            if(player.isHost) {
             for(Player players : roomController.getPlayersForIP(player.roomID).values()) {
              if(!players.isHost && players.playerPort > 0) {
               ctx.writeAndFlush(new PBUDPServerPacket(opcode, Unpooled.copiedBuffer(msg.content()), new InetSocketAddress(players.playerIP, players.playerPort), (byte)slot, ignore, accountId).getPacket());
              }
             }
            } else {
             Player host = roomController.getHostForIP(player.roomID);
             if(host.playerPort > 0) {
              ctx.writeAndFlush(new PBUDPServerPacket(opcode, Unpooled.copiedBuffer(msg.content()), new InetSocketAddress(host.playerIP, host.playerPort), (byte)slot, ignore, accountId).getPacket());
             }
            }
           }
          }
          break;
         }
         case 97: {
          log.info("opcode: " + opcode + " sender: " + msg.sender().getAddress().getHostAddress());
          ctx.writeAndFlush(new PBUDPServerPacket(opcode, Unpooled.copiedBuffer(msg.content()), new InetSocketAddress(msg.sender().getAddress(), msg.sender().getPort()), (byte)slot, ignore, accountId).getPacket());
          break;
         }
         case 67: {
          log.info("try remove player " + msg.sender().getAddress().toString());
          RoomController.getInstance().removePlayer(msg.sender().getAddress());
          break;
         }
         default: {
          log.warn("unknown opcode: " + opcode);
         }

        }
       }
      catch(Exception e) {
       log.error(e.toString());
      }
      finally {
       bb.clear();
      }
     }

ERROR:

[18:16:46|ERROR|nioEventLoopGroup-2-1 |io.netty.util.ResourceLeakDetector             ] LEAK: ByteBuf.release() was not called before it's garbage-collected.

如何修复错误?这对我来说非常重要。

堆栈跟踪:

[17:14:59|ERROR|nioEventLoopGroup-2-1 |io.netty.util.ResourceLeakDetector             ] LEAK: ByteBuf.release() was not called before it's garbage-collected.
Recent access records: 1
#1:
 io.netty.buffer.AdvancedLeakAwareByteBuf.writeBytes(AdvancedLeakAwareByteBuf.java:559)
 io.netty.buffer.Unpooled.copiedBuffer(Unpooled.java:421)
 ru.pb.battle.network.client.BattleClientConnection.channelRead0(BattleClientConnection.java:89)
 ru.pb.battle.network.client.BattleClientConnection.channelRead0(BattleClientConnection.java:42)
 io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:103)
 io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:338)
 io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:324)
 io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785)
 io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe.read(AbstractNioMessageChannel.java:93)
 io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:485)
 io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:452)
 io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:346)
 io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
 java.lang.Thread.run(Thread.java:744)
Created at:
 io.netty.util.ResourceLeakDetector.open(ResourceLeakDetector.java:190)
 io.netty.buffer.AbstractByteBufAllocator.toLeakAwareBuffer(AbstractByteBufAllocator.java:42)
 io.netty.buffer.UnpooledByteBufAllocator.newDirectBuffer(UnpooledByteBufAllocator.java:55)
 io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:155)
 io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:146)
 io.netty.buffer.Unpooled.directBuffer(Unpooled.java:127)
 io.netty.buffer.Unpooled.copiedBuffer(Unpooled.java:417)
 ru.pb.battle.network.client.BattleClientConnection.channelRead0(BattleClientConnection.java:89)
 ru.pb.battle.network.client.BattleClientConnection.channelRead0(BattleClientConnection.java:42)
 io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:103)
 io.netty.channel.DefaultChannelHandlerContext.invokeChannelRead(DefaultChannelHandlerContext.java:338)
 io.netty.channel.DefaultChannelHandlerContext.fireChannelRead(DefaultChannelHandlerContext.java:324)
 io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:785)
 io.netty.channel.nio.AbstractNioMessageChannel$NioMessageUnsafe.read(AbstractNioMessageChannel.java:93)
 io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:485)
 io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:452)
 io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:346)
 io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
 java.lang.Thread.run(Thread.java:744)

====================== PBUDPServerPacket

public class PBUDPServerPacket {
    private ByteBuf buff;
    private InetSocketAddress addr;

    public PBUDPServerPacket(int opcode, ByteBuf data, InetSocketAddress recipient, byte slot, byte[] ignore, int accountId) {
        buff = Unpooled.buffer().order(ByteOrder.LITTLE_ENDIAN);
        buff.writeByte(opcode);
        buff.writeByte(slot);
        buff.writeBytes(ignore);
        buff.writeByte(accountId);
        buff.writeBytes(data);
        addr = recipient;
    }

    public DatagramPacket getPacket() {
        return new DatagramPacket(buff, addr);
    }
}

2 个答案:

答案 0 :(得分:3)

您需要在release块中ByteBuf而不是clear调用finally,否则引用计数缓冲区不会被正确解除分配。

答案 1 :(得分:0)

如果您使用的是 DataBuffer ,则可能会遇到相同的错误。 Spring具有 DataBufferUtils 库以释放资源。

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/core/io/buffer/DataBufferUtils.html

import org.springframework.core.io.buffer.DataBufferUtils;

DataBufferUtils.release(dataBuffer);