前言
配置在边缘节点的端口转发、数据包修改服务软件,发生 周期性 的服务中断。周期介于5~10天之间,尤易在周末发生。推测与流量有关。
中断时报错: Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
应急处理
先发维护通知忽悠用户,然后趁机定期进行重启,清理内存。
肇事代码
//启动本地监听端口
ServerSocket serverSocket = new ServerSocket(localPort);
log.info("localPort="+localPort + ";remoteIp=" + remoteIp +
";remotePort="+remotePort+";启动本地监听端口" + localPort + "成功!");
while(true){
Socket clientSocket = null;
Socket remoteServerSocket = null;
try {
//获取客户端连接
clientSocket = serverSocket.accept();
//建立远程连接
remoteServerSocket = new Socket(remoteIp ,remotePort);
String clientIP = clientSocket.getLocalAddress().toString();
clientIP = clientIP.substring(clientIP.lastIndexOf("/")+1);
log.info("客户端IP:"+clientIP);
//启动数据转换接口
(new TransPortData(clientSocket ,remoteServerSocket ,"1")).start();
(new TransPortData(remoteServerSocket ,clientSocket,"2")).start();
} catch (Exception ex) {
log.info("",ex);
}
//建立远程连接
}
原因分析
从图中可以看出存在大量的byte[],而上面代码中启动数据转换接口的同时,正是使用了一个byte[]变量储存TCP数据包。
InputStream in = getDataSocket.getInputStream() ;
//读入数据
byte[] data = new byte[2048];
int readlen = in.read(data);
为了进一步确认这个错误,在启动指令中加入分析功能,反馈如下:
nid达到百万级别,可以认为确实是线程清理不干净导致的。
代码优化
加入 while 1 退出机制
//如果没有数据,则暂停,超时销毁资源
if(readlen<=0){
TimeoutStamp++;
if(TimeoutStamp>=300){
break;
}
Thread.sleep(100);
continue;
}
并在finally中关闭数据包传输器
finally{
//关闭socket
try {
if(putDataSocket != null){
putDataSocket.close();
}
} catch (Exception exx) {
}
try {
if(getDataSocket != null){
getDataSocket.close();
}
} catch (Exception exx) {
}
}
实测内存占用稳定,不再发生内存泄漏。