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