场景,线上堆栈10G,平时内存使用达到8个G而且慢慢增长,经常出现full gc,经过堆栈信息排查出来是由于ObjectOutputStream造成得内存泄漏。项目中使用ObjectOutputStream进行写文件,使用writeObject()方法,然而,该对象写得object可能存在内存泄漏,是由于ObjectOutputStream写对象时,依然存在这对该对象得引用,这是java得自身优化,可以减少socket得网络开销,譬如如下代码,然后看截图,我们虽然写了10次,但是并不是每次都会记录对象和成员变量得信息,而是第一次记录,之后不再记录,这时java得优化,减少socket网络开销,然而可以这么做时因为该outputstream持有myobject得引用,当数据量很大得时候必然会产生内存泄漏。
解决方法是,使用reset方法,重置状态,第二张图片就是重置后得信息,很明显,使用reset后,会增加网络网络开销,所以对于是否使用reset方法,请根据实际业务决定,当长期不停服务,最好使用reset,而对于短期内停止服务,数据量很大得,可以不是用reset。
当数量为1000000时,内存使用两下图。
内容参考如下引用:
http://www.ibm.com/developerworks/cn/java/j-lo-streamleak/
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("test.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
//try {
//Thread.sleep(20000);
//} catch (InterruptedException e2) {
TODO Auto-generated catch block
//e2.printStackTrace();
//}
System.out.println(new Date());
//for (int i = 0; i < 1000000; i++) {
for (int i = 0; i < 10; i++) {
MyObject myObj = new MyObject();
myObj.str1 = "test1";
myObj.str2 = "test2";
oos.writeObject(myObj);
// oos.reset();
}
try {
Thread.sleep(20000);
System.out.println(new Date());
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
fos.close();
try {
Thread.sleep(20000);
System.out.println(new Date());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
没使用reset
使用reset
未使用reset 次数100w
使用reset,次数100w