当前位置:首页 > 开发 > 编程语言 > 网络编程 > 正文

Socket长连接内存泄漏原因

发表于: 2012-11-29   作者:sunjing   来源:转载   浏览次数:
摘要: 摘录自http://lbdf001.javaeye.com/blog/548003     socket通信是通过ObjectOutputStream和ObjectInputStream来进行写、读操作的。 首先看一下对象序列化写入,下例将一简单对象序列化到文本文件中: public class TestSocket {    &nbs

摘录自http://lbdf001.javaeye.com/blog/548003

    socket通信是通过ObjectOutputStream和ObjectInputStream来进行写、读操作的。 首先看一下对象序列化写入,下例将一简单对象序列化到文本文件中:

public class TestSocket {

     public static void main(String[] args) throws Exception {
         FileOutputStream fos = new FileOutputStream("c:\\test.txt");
         ObjectOutputStream oos = new ObjectOutputStream(fos);

         MyObject myObj = new MyObject();
         myObj.setStr1("test1");
         myObj.setStr2("test2");

         for (int i = 0; i < 1; i++) {
             oos.writeObject(myObj);
         }

         oos.close();
     }
}

class MyObject implements Serializable {
     private static final long serialVersionUID = 1620871590853110557L;

     private String str1;
     private String str2;

     public String getStr1() {
          return str1;
     }

     public void setStr1(String str1) {
          this.str1 = str1;
     }

     public String getStr2() {
          return str2;
     }

     public void setStr2(String str2) {
          this.str2 = str2;
     }
}

     当写入一个对象时,文本文件内容如下:

 sr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test1t test2

     当写入10个相同对象时,文本文件内容如下:
 sr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test1t test2q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~ q ~


     修改代码,写入10个属性值相同的新对象,
for (int i = 0; i < 10; i++) {
     MyObject myObj = new MyObject();
     myObj.setStr1("test1");
     myObj.setStr2("test2");
     oos.writeObject(myObj);
}

     文本文件内容如下:
 sr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test1t test2sq ~ q ~ q ~ sq ~ q ~ q ~ sq ~ q ~ q ~ sq ~ q ~ q ~

sq ~ q ~ q ~ sq ~ q ~ q ~ sq ~ q ~ q ~ sq ~ q ~ q ~ sq ~ q ~ q ~

     修改代码,写入10个新对象,且属性值不同
for (int i = 0; i < 10; i++) {
     MyObject myObj = new MyObject();
     myObj.setStr1("test1" + i);
     myObj.setStr2("test2" + i);
     oos.writeObject(myObj);
}
     文本文件内容如下:
 sr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test10t test20sq ~ t test11t test21sq ~ t test12t test22sq ~ t

test13t test23sq ~ t test14t test24sq ~ t test15t test25sq ~ t test16t test26sq ~ t test17t test27sq ~ t test18t test28sq ~ t test19t

test29

     通过对比,不是每次都会写入对象的完整信息,而只是在第一次写入了类名、字段名、字段类型等,以后就不会再写入了。这实际是java做的优化,通过该优化从而减少socket传输的开销,要达到这个目的,ObjectOutputStream须持有以前发送对象的引用。如果采用socket长连接的方式,jvm在进行垃圾回收的时候不能回收之前发送的对象的实例,经过漫长时间的运行,最终就会导致内存溢出。
     那如何避免该问题呢,ObjectOutputStream有一reset方法,JDK文档中是这么解释该方法的:
“重置将丢弃已写入流中的所有对象的状态。重新设置状态,使其与新的 ObjectOutputStream 相同。将流中的当前点标记为 reset,相应的 ObjectInputStream 也将在这一点重置。以前写入流中的对象不再被视为正位于流中。它们会再次被写入流。”
     就是说调用reset释放掉了对象的引用。
     修改代码,在每次写入后都调用一下reset()
for (int i = 0; i < 10; i++) {
     MyObject myObj = new MyObject();
     myObj.setStr1("test1" + i);
     myObj.setStr2("test2" + i);
     oos.writeObject(myObj);
     oos.reset();
}

     我们再来看一下写入文件内容:

 sr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test10t test20ysr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test11t test21ysr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test12t test22ysr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test13t test23ysr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test14t test24ysr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test15t test25ysr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test16t test26ysr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test17t test27ysr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test18t test28ysr org.sunjc.MyObject~~荝k L str1t Ljava/lang/String;L str2q ~ xpt test19t test29ysr

     这次跟之前不同,每一次都写入了对象的完整信息。
     通过上面一系列的测试,在不调用reset的方式时,java的优化对于减轻socket开销是很可观的,当然是有代价的,那就是直到你调用reset 或者是关闭输出流之前,对于发送过的对象的实例是不会释放的。

     结论:当然只是我自己的片面之词。如果你的程序要长时间运行,建议调用reset避免最后内存溢出程序崩溃,但是如果你又要长时间运行,发送的消息量又很大,那么调用reset无疑会增加开销,那么这个时候最好的做法是自己实现一套机制,定时或者是定量(比如查看到内存已经涨到一个水平)的调用reset,这样既可以避免内存无限的增长下去,又可以减少socket通信的开销。

Socket长连接内存泄漏原因

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
长连接与短连接 Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通
http://bbs.chinaunix.net/thread-709365-1-1.html http://topic.csdn.net/t/20040810/19/3261335.h
JAVA内存泄漏——内存泄漏原因和内存泄漏检测工具(zt) 摘要   虽然Java虚拟机(JVM)及其垃圾收集器
TCP/IP TCP/IP是个协议组,可分为三个层次:网络层、传输层和应用层。 在网络层有IP协议、ICMP协议
先看图: TCP/IP是什么? TCP/IP是个协议组,可分为三个层次:网络层、传输层和应用层。 在网络层有
转 TCP/IP是什么? TCP/IP是个协议组,可分为三个层次:网络层、传输层和应用层。 在网络层有IP协议
先看图: TCP/IP是什么? TCP/IP是个协议组,可分为三个层次:网络层、传输层和应用层。 在网络层有
先看图: TCP/IP是什么? TCP/IP是个协议组,可分为三个层次:网络层、传输层和应用层。 在网络层有
内存泄漏也称作“存储渗漏”,用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一
ECONNABORTED 该错误被描述为“software caused connection abort”,即“软件引起的连接中止”。原
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号