前段时间java程序,内存泄漏比较严重,平均3-5天就要重启一下,赶快分析原因。从公司的监控看到,主要是对外内存泄漏,因为堆内存泄漏不是很严重。所以决定优先处理前者。因为该项目是java开发的,主要任务时加载tensorflow1.*的模型,并实时预测。其实主要JNI调用c++接口,所以很大可能是在接口调用时泄漏了,看代码:
Tensor?res?=null;
???? try?{
List<String>?colname=IntColname;
Runner?rlt?=?sess.runner();
for(int?i=0;?i<intvalue[0].length;?i++)?{
int[][]?index=new?int[intvalue.length][1];
for(int?m=0;?m<intvalue.length;?m++)?{
index[m][0]=intvalue[m][i]; ????
}
Tensor?indexTensor?=?Tensor.create(index);?
rlt.feed(colname.get(i),?indexTensor);
}
colname=FloatColname;
for(int?i=0;?i<floatvalue[0].length;?i++)?{
float[][]?index=new?float[floatvalue.length][1];
for(int?m=0;?m<floatvalue.length;?m++)?{
index[m][0]=floatvalue[m][i]; ???
}
Tensor?indexTensor?=?Tensor.create(index);?
rlt.feed(colname.get(i),?indexTensor);
temp.add(indexTensor);
}
?
????res=rlt.fetch("output").run().get(0);
float[][]?finalRlt?=?new?float[intvalue.length][1];
res.copyTo(finalRlt);
List<Float>?result=new?ArrayList<Float>();
for(int?i=0;?i<finalRlt.length;?i++)?{
result.add(finalRlt[i][0]);
}
return?result;
}?catch?(Exception?e)?{
logger.error("",e);
}finally?{
if?(res?!=?null)?{
?????????????????res.close();
????????????}
}虽然res调用了close方法,但是?indexTensor 却没有调用,因此调整代码。
Tensor?res?=null;
???? List<Tensor>?temp=new?ArrayList<>();
???? try?{
List<String>?colname=IntColname;
Runner?rlt?=?sess.runner();
for(int?i=0;?i<intvalue[0].length;?i++)?{
int[][]?index=new?int[intvalue.length][1];
for(int?m=0;?m<intvalue.length;?m++)?{
index[m][0]=intvalue[m][i]; ????
}
Tensor?indexTensor?=?Tensor.create(index);?
rlt.feed(colname.get(i),?indexTensor);
temp.add(indexTensor);
}
colname=FloatColname;
for(int?i=0;?i<floatvalue[0].length;?i++)?{
float[][]?index=new?float[floatvalue.length][1];
for(int?m=0;?m<floatvalue.length;?m++)?{
index[m][0]=floatvalue[m][i]; ???
}
Tensor?indexTensor?=?Tensor.create(index);?
rlt.feed(colname.get(i),?indexTensor);
temp.add(indexTensor);
}
?
????res=rlt.fetch("output").run().get(0);
float[][]?finalRlt?=?new?float[intvalue.length][1];
res.copyTo(finalRlt);
List<Float>?result=new?ArrayList<Float>();
for(int?i=0;?i<finalRlt.length;?i++)?{
result.add(finalRlt[i][0]);
}
return?result;
}?catch?(Exception?e)?{
logger.error("",e);
}finally?{
if?(res?!=?null)?{
???????????? res.close();
????????????}
for(int?i=0;?i<temp.size();?i++)?{
Tensor?t=temp.get(i);
if(t!=null)?{
t.close();
}
}
}主要是增加temp队列回收临时变量。上线后发现泄漏不是很严重了,说明很有效果。不过还有,后面是java堆内存泄漏,发现每次泄漏的时间正是模型切换的时间,因此大概率是模型切换的代码有问题,上代码。
public?static?void?clearCache()?{
logger.info("===model?clear===");
sess=null;
}这里的session就是模型解析好的session会话,由下面的代码生成。
byte[]?graphBytes?=?IOUtils.toByteArray(inputStream); Graph?graph=new?Graph(); graph.importGraphDef(graphBytes);???? sess?=?new?Session(graph);
立刻明白,上面的代码有问题,调整为如下:
public?static?void?clearCache()?{
logger.info("===model?clear===");
if(sess!=null)?{
logger.info("destory?session");
sess.close();
sess=null;
}
}少了一个close,造成session关联的对象无法释放,至此内存泄漏问题算是解决了。
原文:https://blog.51cto.com/u_12597095/2807842