`

【优化】多线程访问数据库导致内存泄露的优化过程

 
阅读更多
本文转自:http://www.blogjava.net/persister/archive/2010/01/14/309530.html

1、这家公司有一个数据库代理程序,用于数据库服务器的代理,游戏服务器执行sql指令,DBAgent接受此指令,执行一些组织后,调用JDBC执行数据库操作,然后将结果返回。

2、发生的问题:内存一直升高,处理客户端请求的线程并不多(高峰期大概300左右吧),数据库上的连接数也不多(100的样子)。运行5-6天,基本上内存就用完了,而且得不到数据库的连接。他们非常急,我就试着接下这个项目。

3、接到这个优化项目,查看了他们的部分代码。发现连接池写得有些问题,得不到数据库连接后wait,但是不会接到任何有效的notify,也就是说只要一等待就会超时。还有其他的问题,一开始我以为是这个问题,修改后让他们去跑,结果还是一样,内存上去后一直下不来,最后崩溃。

4、通过这个发现就是内存泄露了。一开始用jprofiler测试,发现内存上去后就Out of memory了,而且hashmap和long[]的对象非常多一直下不去。但是找不到这些对象是怎么产生的。折磨了我好几天,还请教了很多人,都得不到答案。后来发现是java启动参数中内存参数设置的太低了,本来需要100多M的内存,你就设置给16M,不崩溃才怪呢。于是改成了128M。结果内存上去之后,到达一个峰值就下来了,然后震荡,但一直就没有上去。那程序没有泄露?可是生产上怎么泄露了呢?

5、就在我基本上要放弃的时候,我想到了测试环境可能真实环境不同,有必要看一下他们生产服务器上虚拟机的运行情况。记得Java有自带的工具查询java虚拟机运行情况的。jmap这个工具可以查看jvm中运行实例的个数以及实例的类名。让他们的人用了下这个工具,将结果发给我了,我一看,吓了一大跳。排在第一位的是int[],竟然达到了1G。最有问题的是com.mysql.jdbc.PreparedStatement对象,达到了6万多。com.mysql.jdbc.ResultSetImpl和java.util.HashMap$Entry[]也达到了6万多。不用说,肯定是PreparedStatement没有关闭。

6、查看源代码,发现PreparedStatement对象都在finally块中关闭了,怎么会泄露呢?找了1个小时没有找到,就去洗澡了。在洗澡的时候突然想到,里面有一个for循环,PreparedStatement对象可能被赋值N次,那前面的N-1次不就没有关闭啊,对,找到答案了。赶紧擦干身子出来找到那段代码:

1  String[] valuesArray = value.split(";");
 2  for (int i = 0 ;i < valuesArray.length;i++){
 3 
 4 String[] valueArray = valuesArray[i].split(",");
10                     ps = conn.prepareStatement(sqlbean.getSql());
11                     for(int k = 0;k <valueArray.length;k++){
12                         if("s".equalsIgnoreCase(paraTypeArray[k])){
13                             ps.setString(k+1,valueArray[k]);
14                         }else if("i".equalsIgnoreCase(paraTypeArray[k])){
15                             ps.setInt(k+1,Integer.parseInt(valueArray[k]));
16                         }
17                     }
18 
19                     rsString = "" + ps.executeUpdate();
20 
21 }


确实如此,循环的N-1个PreparedStatement对象没有关闭,导致了泄漏。解决办法就是将
ps = conn.prepareStatement(sqlbean.getSql());

移到for循环的外面,这样就没有问题了。不过从这段代码也可以看出,写得也是在是烂,这个干吗放到
循环的里面呢,本身从语言上来说就有问题。管它呢,解决问题就行了,呵呵。
几乎兴奋了一个晚上。第二天找他们的人一说,他们说是循环N次的,不只是一个值。问题不就解决了?Great。

7、让他们去测试运行吧。运行第一天的晚上九点(这是高峰期)以后,内存非常平稳。问题彻底解决了。

总结这次的优化项目:
对Java虚拟机的认识提高了。对java性能测试工具(JProfiler)更加熟练了,可以和eclipse集成呢,非常方便。
分享到:
评论

相关推荐

    在PB中实现 多线程的例子

    例如,`Mutex`用于在多线程访问同一资源时提供独占访问,确保任何时候只有一个线程可以访问。 ```pb Mutex mutex = Create Mutex mutex.Lock() // 获取锁 // 访问共享资源 mutex.Unlock() // 释放锁 ``` **4. 线程...

    delphi7 多线程测试(40个线程)

    3. **资源竞争**:当多个线程访问相同的资源,如内存、磁盘I/O或数据库连接时,可能会出现竞态条件,需要通过锁或其他同步机制来解决。这会导致线程等待,增加了整体执行时间。 4. **工作负载平衡**:如果40个线程...

    C#内存释放-线程控制-线程启动-线程暂停

    在C#编程中,线程控制和内存管理是两个至关重要的概念,特别是在处理并发和优化应用程序性能时。本文将深入探讨“C#内存释放-线程控制-线程启动-线程暂停”这一主题,结合提供的WFormsThread文件,我们可以假设这是...

    oracle 数据库优化方法

    4. 定期更新系统补丁,修复可能导致内存泄漏的漏洞。 此外,通过`vmstat`、`glance`、`topas`或`ps`等工具,可以找出占用系统资源过高的Oracle会话及其执行的SQL语句。通过查询Oracle的动态性能视图,如V$SESSION和...

    jboss内存溢出优化

    3. **线程栈大小配置不适宜**:线程栈大小设置过大或过小,都可能导致内存溢出。 4. **持久层问题**:如Hibernate等ORM框架的不当使用,可能造成内存泄漏。 5. **类加载器泄露**:类加载器未能正确卸载已不再使用的...

    mfc多线程聊天程序

    在实际的"多线程聊天程序"项目中,你可能还会涉及到SSL/TLS加密、身份验证、消息的序列化和反序列化、数据库交互等多个方面的知识。这些都需要根据具体需求和技术栈进行深入研究和实现。通过这样的项目实践,你不仅...

    OC多线程管理

    2. 内存管理:多线程可能导致内存问题,如引用计数错误。ARC(Automatic Reference Counting)在多线程环境下仍然有效,但要注意线程间同步操作,避免内存泄漏。 七、最佳实践 1. 尽可能使用GCD和NSOperationQueue...

    powerbuilder多线程示例10个thread

    在PowerBuilder(PB)开发环境中,多线程技术是一种关键的编程技巧,它允许应用程序同时执行多个任务,提高系统的响应速度和效率。本资源“powerbuilder多线程示例10个thread”提供了十个具体的PowerBuilder多线程...

    DBA优化数据库性能心得

    同时,保持系统补丁的更新,避免因内存泄漏问题导致的性能下降。 定位消耗资源过多的Oracle会话和其执行的SQL语句,Unix下的`glance`、`top`、`topas`和`ps`命令都能提供帮助。通过这些工具找到进程ID后,可以在...

    winform之多线程编程 (源码)

    在.NET框架中,WinForm应用通常运行在单线程应用程序上下文(STA)中,这意味着所有用户界面(UI)更新必须在主线程中执行。...在实际项目中,还需要根据具体需求调整和优化多线程策略,以达到最佳效果。

    Qt多线程实例

    - **数据库访问**:数据库操作通常会阻塞主线程,使用多线程可以避免这种情况,提升用户体验。 4. **线程管理**: - **避免QObject的跨线程操作**:Qt的对象模型是线程相关的,直接在不同线程间操作QObject可能...

    ruby 内存分配访问无效

    检查数据库连接的打开和关闭,以及任何可能导致内存泄漏的数据库查询是必要的。 总之,解决“ruby内存分配访问无效”的问题需要深入理解Ruby的内存管理和垃圾回收机制,结合代码审查、调试工具和适当的内存分析,找...

    通过多线程为基于 .NET 的应用程序实现响应迅速的用户

    本文将深入探讨如何利用多线程来优化基于.NET的应用程序,为用户提供更加流畅的交互体验。 首先,理解多线程的基本概念至关重要。在单线程环境中,程序按照一个顺序执行任务,如果遇到耗时操作(如数据库查询或网络...

    C++多线程编程总结.pdf

    在多线程编程中,C++11的auto关键字可以帮助我们避免因复杂类型而导致的错误。 8. 并发算法和并行算法:C++标准库提供了算法,如std::for_each,用于处理容器中的数据。在支持多线程的环境中,可以使用并行版本的...

    windows多线程编程原理与应用

    多线程技术广泛应用于网络服务、图形渲染、数据库访问等多个领域。例如,在游戏开发中,可以使用多线程来处理游戏逻辑、用户输入和图形渲染,提高游戏性能。在服务器端,多线程可以处理并发的客户端请求,提升服务...

    PowerBuilder多线程简单应用

    在PB中,多线程能够帮助开发者更好地管理资源,提高用户体验,特别是在进行I/O操作、数据库查询或网络通信时。 2. **SharedObjectRegister函数**:这个函数用于在PowerBuilder中注册一个共享对象,它是多线程支持的...

    安卓Andriod源码——下载网络图片(整合多线程、内存缓存、本地文件缓存~).zip

    `ImageViewLoader`可能使用了`BitmapFactory.Options`来控制解码过程,避免加载过大导致内存溢出。 5. **异步加载策略**: 图片加载库通常会采用异步加载策略,比如` placeholders`(占位图)和`error images`...

    iphone多线程编程

    多线程编程对于优化iOS应用性能至关重要。通过理解线程的基本概念、掌握不同的实现方法,并有效进行线程同步,开发者可以构建出高效稳定的应用程序。希望本文能帮助大家更好地理解和运用多线程技术。

    Android优化大师源代码.rar

    6.2 数据库连接池:多线程访问数据库时,使用连接池避免频繁创建和关闭连接。 七、代码结构与设计模式 7.1 单例模式:确保全局唯一,减少资源浪费。 7.2 MVP或MVVM架构:分离视图、模型和逻辑,提高可维护性和...

    android 优化内存方案

    这些知识点涵盖了Android内存优化的多个层面,通过深入理解和实践,开发者可以显著提升应用的性能和用户体验。这份PDF文档应该会详细解释这些概念,并提供实际案例和最佳实践,帮助开发者解决常见的内存问题。

Global site tag (gtag.js) - Google Analytics