beykery / jkcp

kcp for java . 适用于moba,视频加速等需要极速传输场景的应用,c#版本(客户端)请参考:https://github.com/beykery/kcp4sharp
Apache License 2.0
186 stars 85 forks source link

一直报这个错,是哪里使用有问题吗,我项目里本身没有用到 netty,这个错误应该是jkcp 层报出来的 #19

Open dingzhichao opened 6 years ago

dingzhichao commented 6 years ago

[nioEventLoopGroup-2-1] WARN io.netty.util.ReferenceCountUtil - Failed to release a message: DatagramPacket(/0.0.0.0:6000 => /127.0.0.1:64272, PooledUnsafeDirectByteBuf(freed)) io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1

beykery commented 6 years ago

请把代码贴出来。

dingzhichao commented 5 years ago

public void handleReceive(ByteBuf byteBuf, KcpOnUdp kcpOnUdp) { int sessionId = kcpOnUdp.getKcp().getConv(); int length = byteBuf.readableBytes();//得到可读字节数 byte[] bytes = new byte[length]; //分配一个具有length大小的数组 byteBuf.getBytes(0, bytes); //将缓冲区中的数据拷贝到这个数组中 byteBuf.release(); FSPSession session = null; boolean isNewSession = false; if (sessionMap.containsKey(sessionId)) { session = sessionMap.get(sessionId); } else { session = new FSPSession(sessionId, kcpOnUdp); sessionMap.put(sessionId, session); isNewSession = true; } session.handleReceive(bytes, isNewSession);

}
dingzhichao commented 5 years ago

public class UdpServer extends KcpServer {

Map<Integer, FSPSession> sessionMap = new HashMap<>();

private static Logger log = LoggerFactory.getLogger(UdpServer.class);

public UdpServer(int port, int workSize) {
    super(port, workSize);
}

@Override
public void handleReceive(ByteBuf byteBuf, KcpOnUdp kcpOnUdp) {
    int sessionId = kcpOnUdp.getKcp().getConv();
    int length = byteBuf.readableBytes();//得到可读字节数
    byte[] bytes = new byte[length];    //分配一个具有length大小的数组
    byteBuf.getBytes(0, bytes); //将缓冲区中的数据拷贝到这个数组中
    byteBuf.release();
    FSPSession session = null;
    boolean isNewSession = false;
    if (sessionMap.containsKey(sessionId)) {
        session = sessionMap.get(sessionId);
    } else {
        session = new FSPSession(sessionId, kcpOnUdp);
        sessionMap.put(sessionId, session);
        isNewSession = true;
    }
    session.handleReceive(bytes, isNewSession);

}

@Override
public void handleException(Throwable throwable, KcpOnUdp kcpOnUdp) {
    log.error(throwable.getMessage());
}
dingzhichao commented 5 years ago

麻烦请问下,该开源项目有线上游戏项目在用

beykery commented 5 years ago

很显然你需要把 byteBuf.release();这行注销掉

dingzhichao commented 5 years ago

很显然你需要把 byteBuf.release();这行注销掉

这个 byteBuf.release() 是后面加上才去的, 没加之前都报哪个错,我去掉之后也会报。 WARN io.netty.util.ReferenceCountUtil - Failed to release a message: DatagramPacket(/0.0.0.0:6666 => /127.0.0.1:51373, PooledUnsafeDirectByteBuf(freed))

大佬,你看下这个,貌似说 dp 释放失败。

beykery commented 5 years ago

int length = byteBuf.readableBytes();//得到可读字节数 byte[] bytes = new byte[length]; //分配一个具有length大小的数组 byteBuf.getBytes(0, bytes); //将缓冲区中的数据拷贝到这个数组中 byteBuf.release(); 这段是啥? 你应该参考下我写的demo。

beykery commented 5 years ago

ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED); 启动的时候加上这个试试?

dingzhichao commented 5 years ago

int length = byteBuf.readableBytes();//得到可读字节数 byte[] bytes = new byte[length]; //分配一个具有length大小的数组 byteBuf.getBytes(0, bytes); //将缓冲区中的数据拷贝到这个数组中 byteBuf.release(); 这段是啥? 你应该参考下我写的demo。

嗯~ 其实就是参考你的那个testServer demo 来写的,因为你的demo里面对收到消息处理很简单,直接是字符串,我接受消息是结构体,所以需要解析 netty 的ByteBuf, int length = byteBuf.readableBytes();//得到可读字节数 byte[] bytes = new byte[length]; //分配一个具有length大小的数组 byteBuf.getBytes(0, bytes); //将缓冲区中的数据拷贝到这个数组中 这段的意思就是把ByteBuf 的所欲 读到 字节数组中来,以便给后续逻辑处理

dingzhichao commented 5 years ago

ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED); 启动的时候加上这个试试?

这个其实加过,但是还是一样报错。

dingzhichao commented 5 years ago

int length = byteBuf.readableBytes();//得到可读字节数 byte[] bytes = new byte[length]; //分配一个具有length大小的数组 byteBuf.getBytes(0, bytes); //将缓冲区中的数据拷贝到这个数组中 byteBuf.release(); 这段是啥? 你应该参考下我写的demo。

嗯~ 其实就是参考你的那个testServer demo 来写的,因为你的demo里面对收到消息处理很简单,直接是字符串,我接受消息是结构体,所以需要解析 netty 的ByteBuf, int length = byteBuf.readableBytes();//得到可读字节数 byte[] bytes = new byte[length]; //分配一个具有length大小的数组 byteBuf.getBytes(0, bytes); //将缓冲区中的数据拷贝到这个数组中 这段的意思就是把ByteBuf 的所欲 读到 字节数组中来,以便给后续逻辑处理

dingzhichao commented 5 years ago

int length = byteBuf.readableBytes();//得到可读字节数 byte[] bytes = new byte[length]; //分配一个具有length大小的数组 byteBuf.getBytes(0, bytes); //将缓冲区中的数据拷贝到这个数组中 byteBuf.release(); 这段是啥? 你应该参考下我写的demo。

其实这段的 主要目的 就是把 数据 读到 byte数组,然后后面逻辑 用这个byte数组 进行反序列化 public void OnReceive(byte[] bytes, boolean isNewSession) { try { kcpNeedUpdateFlag = true; FSPDataC2S dataC2S = FSPDataC2S.parseFrom(bytes); //反序列化 onReceiveFSPData(dataC2S, isNewSession);//对接收到的数据进行 逻辑处理 } catch (Exception e) { e.printStackTrace(); } }

beykery commented 5 years ago

其实也不影响什么,它自己会保证不用的buf被release;不过我真没找到到底哪里的问题。

dingzhichao commented 5 years ago

嗯,通信过程中报错了,但是确实没有发生丢包,就是报错报到后面,内存溢出了,所以担心后面 通信的客户端数量上去了,服务器会crash掉

beykery commented 5 years ago

ResourceLeakDetector没关闭的话,没问题的。

365082218 commented 3 years ago

我也有这个问题,就是自己handlerReceive里,如果不对bytebuf.release那么时间久了内存就申请溢出了,如果释放就会出现引用计数这个,然后服务端好像就不正常了,都是累积了一段时间才会这样,我感觉是库本身对bytebuf的申请和释放有问题