`

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

分享到:
评论

相关推荐

    Socket长连接+心跳包+发送读取

    9. **资源管理**:在长连接中,需要妥善管理Socket对象和相关资源,避免内存泄漏和资源耗尽。 10. **异常恢复**:设计合理的重连策略,当连接意外断开时,客户端能够自动尝试重新连接。 在提供的压缩包文件中,...

    进程间负载,基于socket长连接

    基于socket的长连接是指两个进程之间建立一次连接后,长时间保持连接状态,而非每次交互都创建新的连接。这样可以减少连接建立和释放的开销,提高整体性能。 在IPLB中使用基于socket的长连接,通常涉及以下关键知识...

    Android-MinaSocket一款基于Mina的Socket长连接库

    - **资源释放**:当不再需要连接时,应及时关闭并释放资源,避免内存泄漏。 - **异常处理**:对于可能出现的各种网络异常,如连接中断、数据传输错误等,应有完善的异常处理机制。 总结起来,`Android-MinaSocket`...

    librtmp长时间直播socket连接断开的原因

    当遇到“librtmp长时间直播socket连接断开”的问题时,可能的原因包括: 1. **网络不稳定**:长时间的直播对网络连接质量有较高要求。网络波动、信号强度下降或者路由器、交换机等硬件设备故障都可能导致连接中断。...

    Androidsocket通信加长连接(有心跳检测)

    同时,为了防止内存泄漏,需要正确管理和关闭Socket及相关的输入/输出流。 总的来说,Android中的Socket通信结合心跳检测,可以有效地维护长连接的稳定,提高应用程序的用户体验。开发者需要理解Socket通信的基本...

    windows解决socket连接不释放补丁包

    通过安装kb2553549和kb2577795补丁,Windows Server 2008 R2用户可以增强其系统的网络性能,防止由于socket连接管理不当或内存泄漏导致的故障。对于任何运行此类操作系统的IT管理员来说,及时安装这些补丁是维护系统...

    java实现简单socket通信

    每个Socket连接都会在一个独立的线程中处理,以便同时处理多个客户端的请求。服务器端创建新线程来处理每个客户端的连接,客户端也可以在一个单独的线程中读写数据,避免阻塞主线程。 标签中的“p2p”(peer-to-...

    Socket连接实例

    2. **生命周期管理**:确保在适当的时候关闭Socket和流,以防止内存泄漏和资源浪费。例如,在Activity的onPause()或onDestroy()方法中。 3. **异步处理**:由于网络操作可能阻塞主线程,建议使用AsyncTask或Handler/...

    socket判断网络是否连接模块源码和例程

    7. **资源释放**:当不再需要网络连接时,必须使用`关闭套接字`函数释放资源,防止内存泄漏。 由于具体代码并未给出,以上分析基于一般的Socket编程逻辑。如果你有"content.txt"文件的具体内容,可以进一步分析和...

    一个Socket连接管理器(心跳机制)

    7. **资源释放**:当确认连接断开后,需要正确关闭Socket,释放相关资源,防止内存泄漏。 8. **性能优化**:心跳机制的设计需要考虑性能和效率,例如使用异步IO、非阻塞模式等提高处理速度,减少系统资源消耗。 9....

    浅谈内存泄漏

    #### 内存泄漏的原因及示例 内存泄漏通常由以下几种情况引起: 1. **忘记释放内存**:这是最常见的情况,程序员在使用完动态分配的内存后,忘记调用`free()`、`delete`等函数释放内存,如代码片段所示: ```cpp ...

    Mina长连接框架实现Android客户端与服务器端通信

    接着,客户端通过Socket连接到服务器,建立连接后,可以使用I/O处理器进行数据的读写。 在服务器端,Mina提供了一个IoHandler接口,开发者需要实现其中的`messageReceived()`方法来处理接收到的客户端消息,以及`...

    C# Socket学习实例

    为了防止内存泄漏,记得在不再使用Socket时调用`Dispose()`方法。 通过学习以上内容,你可以开始构建自己的C# Socket应用程序,无论是简单的聊天应用还是复杂的网络服务。实践是掌握知识的最佳方式,所以尝试编写一...

    android 2.3以后的socket注意

    在完成Socket通信后,务必关闭输入流、输出流以及Socket本身,以防止内存泄漏和资源浪费。 10. **安全性**: 对于敏感数据传输,应使用SSL/TLS加密的Socket(即SSLSocket)以保证通信安全。 综上所述,Android ...

    浅谈CC++内存泄漏及其检测工具

    #### 内存泄漏的定义与常见原因 内存泄漏在C/C++编程中是一个常见的问题,尤其是在管理动态分配的内存时。所谓内存泄漏,通常指的是堆内存的泄漏。堆内存是程序运行过程中动态分配的一种内存类型,其大小可以在运行...

    C实现基于Socket实现自定义协议通信

    `close()`函数可以释放Socket资源,避免内存泄漏。 总结起来,C语言中的Socket编程涉及了网络通信的基础知识,包括Socket的创建、连接、监听,以及自定义协议的设计和实现。通过熟练掌握这些技术,开发者可以构建...

    C#SOCKET例子

    在程序关闭时,记得释放Socket资源,防止内存泄漏。在C#中,这通常通过重写`Dispose`方法来实现,如示例中所示,关闭Socket并中止处理线程。 总的来说,C#中的Socket编程涉及服务端和客户端的交互,包括创建Socket...

    HP-Socket压力测试 易源代码

    3. 稳定性测试:长时间运行压力测试,检查系统是否会出现内存泄漏、性能下降等问题。 4. 错误恢复测试:模拟网络异常情况,如断线重连,检验系统的恢复能力和错误处理机制。 四、HP-Socket压力测试工具 HP-Socket...

    C# Socket入门学习! Socket入门学习! Socket入门学习!

    当通信完成后,记得关闭Socket和相关的资源,如NetworkStream,以防止内存泄漏和资源浪费。 9. **套接字选项与属性** Socket类还有许多属性和方法,如NoDelay(禁用Nagle算法)、KeepAlive(心跳检测)等,可以...

    socket服务端+客户端

    4. **关闭连接**:通信完成后,客户端和服务器都需要关闭Socket连接,释放资源,防止内存泄漏。 在"压缩包子文件的文件名称列表"中,"C#+Socket异步传输"可能包含了服务端和客户端的源码文件。这些文件通常包括了...

Global site tag (gtag.js) - Google Analytics