netty5.0的任务线程无法回收的问题

来源:互联网 发布:centos ssh 连不上 编辑:程序博客网 时间:2024/05/24 06:11

在最近的项目的运用了netty5.0,之后就发现过两天tomcat就莫名的内存消耗增大,或者直接就进程死掉了。

跟踪了很久发现是netty5在任务线程组里面很多的没有进行回收,然后又创建了很多新的任务线程。但也不是一次性就创建了很多,慢慢的增加的。

通过VisualVM追踪发现很多的nioEventLoopGroup线程,而且很明显的使用中线程不会增加,但是闲下来了,慢慢就会增加。非常奇怪,应该是netty5的一个bug,

我并没有跟踪源码去看,换到4.1之后所有的问题就自然消失了。

附带我netty4.1的客服端代码,有断线重连和空闲发送心跳包,因为是和设备交互,所有的数据都是转码后的。

package com.local.hr.tcp;import org.apache.log4j.Logger;import com.dashu.client.NettyClientBootstrap;import com.local.hr.udp.UdpClientSocket;import com.local.hr.util.ReturnEntity;import io.netty.bootstrap.Bootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioSocketChannel;import io.netty.handler.codec.bytes.ByteArrayEncoder;import io.netty.handler.timeout.IdleStateHandler;public class NettyClient {public static Integer clientId = 0;private Logger log = Logger.getLogger(NettyClientBootstrap.class);private int port;private String host;private String ip;private String mac;private SocketChannel channel;private String userName;private String password;private Bootstrap bootstrap;public boolean isopen = true;public NettyClient(String host, int port, String mac,String userName,String password) throws InterruptedException {String ip ="";try {ReturnEntity entity = UdpClientSocket.getIP(mac, userName, password);//通过udp获取主机地址if (entity!=null) {ip =entity.getIp();}} catch (Exception e) {e.printStackTrace();}this.userName=userName;this.password = password;this.port = port;if (ip!=null&&!"".equals(ip)) {this.host = ip;}else{this.host = host;}this.mac = mac;start(this);}public String getMac() {return mac;}private void start(final NettyClient client) throws InterruptedException {EventLoopGroup eventLoopGroup = new NioEventLoopGroup();bootstrap = new Bootstrap();bootstrap.channel(NioSocketChannel.class);bootstrap.option(ChannelOption.SO_KEEPALIVE, true);bootstrap.group(eventLoopGroup);bootstrap.remoteAddress(host, port);bootstrap.handler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {socketChannel.pipeline().addLast(new IdleStateHandler(150, 150, 300));// 空闲时间    socketChannel.pipeline().addLast(new ByteArrayEncoder());socketChannel.pipeline().addLast(new NettyClientHandler(mac, host, client));}});ChannelFuture future = bootstrap.connect(host, port).sync();if (future.isSuccess()) {this.channel = (SocketChannel) future.channel();isopen = true;log.info("connect server  成功---------");}}public void doConnect() {try {String ip ="";try {ReturnEntity entity = UdpClientSocket.getIP(mac, userName, password);if (entity!=null) {ip =entity.getIp();}} catch (Exception e) {e.printStackTrace();}if (ip!=null&&!"".equals(ip)&&!this.host.equals(ip)) {this.host=ip;}ChannelFuture future = bootstrap.connect(host, port).sync();this.channel = (SocketChannel) future.channel();isopen = true;} catch (Exception e) {log.info("断线重连失败: " + e.getMessage());}}public SocketChannel getChannel() {return channel;}public boolean isopen() {return isopen;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public static void main(String[] args) throws InterruptedException {NettyClient client = new NettyClient("192.168.10.17", 9090, "80.24.00.00", "", "");Thread.sleep(3000);for (int i = 0; i < 10000; i++) {client.channel.writeAndFlush("你好" + i);Thread.sleep(3000);}Thread.sleep(1000000);}}


package com.local.hr.tcp;import java.util.concurrent.TimeUnit;import org.apache.log4j.LogManager;import org.apache.log4j.Logger;import com.local.hr.util.EdHrCode;import com.local.hr.util.NewsCache;import com.local.hr.util.ReturnEntity;import com.local.hr.util.UnHrCode;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.EventLoop;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.handler.timeout.IdleStateEvent;public class NettyClientHandler extends SimpleChannelInboundHandler<Object> {private static final Logger log = LogManager.getLogger(NettyClientHandler.class);private String  mac;private String  hostIp;private NettyClient client;private EdHrCode code = new EdHrCode();private UnHrCode un = new UnHrCode();public NettyClientHandler(String mac,String hostIp,NettyClient client) {this.mac=mac;this.hostIp=hostIp;this.client = client;}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {//断线重连client.isopen = false;final EventLoop eventLoop = ctx.channel().eventLoop();eventLoop.schedule(new Runnable() {@Overridepublic void run() {client.doConnect();while(!client.isopen) {try {Thread.sleep(180000);//等三分钟重新再试} catch (InterruptedException e1) {e1.printStackTrace();}client.doConnect();}}}, 5L, TimeUnit.SECONDS);ctx.close();super.channelInactive(ctx);}// 利用写空闲发送心跳检测消息@Overridepublic void userEventTriggered(ChannelHandlerContext ctx, Object evt)throws Exception {if (evt instanceof IdleStateEvent) {log.debug("空闲了啊!");String h = this.un.heartbeat(this.mac, this.hostIp);ctx.writeAndFlush(this.un.hexStr2ByteArray(h));}}    @Override    public void channelRead(ChannelHandlerContext ctx, Object msg)            throws Exception {        ByteBuf buf = (ByteBuf) msg;        byte[] req = new byte[buf.readableBytes()];        buf.readBytes(req);        String body = code.bytesToHexString(req);        log.debug(this.mac+" 收到消息:"+body);        NewsCache.add(this.mac, body);        ReturnEntity entity= code.caseControlCode("2a", body);        if (entity.getStatus()==ReturnEntity.DATA_STATUS_NORMAL) {        NewsCache.addRead(this.mac, entity);}    }@Overrideprotected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {// TODO Auto-generated method stub}}




0 0
原创粉丝点击