`

Socket长连接内存泄漏原因

    博客分类:
  • Java
阅读更多

摘录自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通信的开销。

分享到:
评论

相关推荐

    easysocketbenchmark:基于redis事件库开发,高性能socket性能测试工具

    满足一般性能测试、延迟测试、最大连接数测试、吞吐量测试、压力测试、长时间稳定性测试、内存泄漏测试等场景。简介:基于redis事件库开发,one epoll per thread模型,超高性能。框架默认支持http性能测试,可轻松...

    c++服务器开发精髓,三个具体案例解析.docx

    1. 内存泄漏检测 2. 内存池技术 3. STL容器的内存分配 ## 数据库连接 数据库连接是c++服务器开发中必不可少的一部分。数据存储和访问是服务器的重要功能之一。数据库连接基础包括以下内容: 1. MySQL数据库连接 2...

    基于HPSOCKET的C/S软件开发框架,功能全面,例程完善···-易语言

    相信很多人都喜欢用内存搞缓存池,但是搞的多了,回收再不及时的话,容易造成内存泄露。所以,这个缓存池采用临时文件读写方式进行操作,效率虽说逊色内存操作,但是其他方面的优越性是内存缓存池无法比拟的!比如在...

    vc网络开发包

    interface for the CNdkIOCPServer class./*警告: 无论在何种情况下,应用程序都不应关闭(closesocket)一个在AcceptEx中使用的, 但尚未被接受的socket句柄,这样会导致内存泄漏,由于性能原因,在未连接的 ...

    服务器概要设计说明.docx

    连接生命周期的管理 C++语言没有对象回收〔GC〕机制,生命周期的管理和防止内存泄露需要程序自己实现,而一条连接从产生后到销毁的过程中会有多个线程同时对其进行操作,同时读写甚至同时关闭,对象的多线程同步也需要...

    93个netty高并发教学视频下载.txt

    84_Netty引用计数注意事项与内存泄露检测方式;85_Netty编解码器剖析与入站出站处理器详解;86_Netty自定义编解码器与TCP粘包拆包问题;87_Netty编解码器执行流程深入分析;88_ReplayingDecoder源码分析与特性解读;...

    基于C++实现的轻量级Web服务器源码+项目说明.zip

    epoll使用EPOLLONESHOT保证一个socket连接在任意时刻都只被一个线程处理 使用线程池提高并发度,并降低频繁创建线程的开销 同步互斥的介绍 使用RAII手法封装互斥器(pthrea_mutex_t)、 条件变量(pthread_cond_t)等...

    涵盖了90%以上的面试题

    内存泄漏和内存溢出 Java的内存模型(JVM的内存划分) JVM内存模型1.7和1.8的区别 如何判断一个对象是否是垃圾对象 垃圾回收算法 Minor GC和Full GC 垃圾收集器 集合的继承体系 Collection 和 Collections的区别。 ...

    基于MySQL的数据库中间件Meituan-DBProxy.zip

    解决连接断开的内存泄露问题 在连接的结构体的释放接口中,lock 的成员变量未释放,导致在连接断开,回收连接对象时会泄漏24个字节 取消admin操作中不必要的日志 去掉了在连接 admin 时报"...

    Alex-Word-Filter-MFC网络版(修正版)

    Alex-Word-Filter-MFC网络版,由北京师范大学计算机学系2000级Alex.Zhang开发,能够过滤纯文本敏感词、标点符号分割敏感词、html敏感词。此版本,提供网络接口服务,能够...此版为修正版,通过vld修正了内存泄漏问题。

    最新名企标准通用C++面试题,

    (2)内存泄漏 void Test(void) { char *str = (char *) malloc(100); strcpy(str, “hello”); free(str); if(str != NULL) { strcpy(str, “world”); printf(str); } } 请问运行Test函数会有什么样...

    精通并发与netty视频教程(2018)视频教程

    84_Netty引用计数注意事项与内存泄露检测方式 85_Netty编解码器剖析与入站出站处理器详解 86_Netty自定义编解码器与TCP粘包拆包问题 87_Netty编解码器执行流程深入分析 88_ReplayingDecoder源码分析与特性解读 89_...

    精通并发与 netty 视频教程(2018)视频教程

    7_Netty的Socket编程详解 8_Netty多客户端连接与通信 9_Netty读写检测机制与长连接要素 10_Netty对WebSocket的支援 11_Netty实现服务器端与客户端的长连接通信 12_Google Protobuf详解 13_定义Protobuf文件及消息...

    (超赞)JAVA精华之--深入JAVA API

    1.9 Java的内存泄漏 1.10 抽象类与接口的区别 1.11 Java变量类型间的相互转换 2 JAVA与WEB 2.1 JMX规范 2.1.1 JMX概述 2.1.2 设备层(Instrumentation Level) 2.1.3 代理层 2.1.4 分布服务层 2.1.5 附加管理协议API...

    精通并发与netty 无加密视频

    第84讲:Netty引用计数注意事项与内存泄露检测方式 第85讲:Netty编解码器剖析与入站出站处理器详解 第86讲:Netty自定义编解码器与TCP粘包拆包问题 第87讲:Netty编解码器执行流程深入分析 第88讲:...

    JAVA SE学习精华集锦

    1.9 Java的内存泄漏 85 1.10 抽象类与接口的区别 86 1.11 Java变量类型间的相互转换 87 2 JAVA与WEB 87 2.1 JMX规范 87 2.1.1 JMX概述 87 2.1.2 设备层(Instrumentation Level) 88 2.1.3 代理层 89 2.1.4 分布服务...

    传智播客扫地僧视频讲义源码

    11_项目中检索内存泄漏使用和基本原理 12_动态库基本知识和环境调试注意 13_动态库内存释放问题 源码及文档 01_上一次课程回顾 02_链表热身_结构体中套元素和指针 03_结构体数据类型的嵌套定义和函数的嵌套调用是两...

    vc++ 开发实例源码包

    检查内存泄漏源码 DigiStatic_src 自绘CStatic实现数字效果。 DirectShow开发指南pdf附属代码 如题。 DirectShow开发指南源码 如题。 directUI_D DirectUI界面库 DOM应用---遍历网页中的元素 如题。 ...

    Android开发艺术探索.任玉刚(带详细书签).pdf

    本书是一本Android进阶类书籍,采用理论、源码和实践相结合的方式来阐述高水准的Android应用开发要点。本书从三个方面来组织内容。... 15.2 内存泄露分析之MAT工具 502 15.3 提高程序的可维护性 506

    Android开发艺术探索

    第1章 Activity的生命周期和启动模式 / 1  1.1 Activity的生命周期全面分析 / 1  1.1.1 典型情况下的生命周期分析 / 2  1.1.2 异常情况下的... 15.2 内存泄露分析之MAT工具 / 502  15.3 提高程序的可维护性 / 506

Global site tag (gtag.js) - Google Analytics