`
dreamlakyxy
  • 浏览: 25907 次
  • 来自: ...
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

困扰了近两月的内存泄露问题终于初见眉目了,罪魁祸首:proxool

阅读更多
困扰了近两月的内存泄露问题终于初见眉目了,罪魁祸首:proxool

生产环境的系统近两个月一直不稳定,过两天内存就会占满,通过jprofiler,jrmc各中方法调试,总是找不到任何原因。

昨天,在做另外一项测试中,终于发现了一个最可能的存在的内存泄露的地方,proxool数据库连接池内存泄露。
测试环境:

tomcat6.0
mysql5.0
昨天分别到官方网站下载dbcp,proxool,c3po最新版本。全部配置tomcat下成jndi数据源,连接数都配置成最大300,最小30
jrokit R27.5

testInsertDB.jsp直接通过数据源连接数据库,通过一个事务往数据库每次插入200万条数据库。
<%
	
	Connection conn = CourseDBService.getConnection();
	Statement stmt = conn.createStatement();

	String sb=new String("insert into t_sys_log values('id");

	conn.setAutoCommit(false);
		
	
	for(int i=5000000;i<7000000;i++){
		StringBuilder sb1=new StringBuilder(sb);
		sb1.append(i).append("','userId").append(i).append("','userName").append(i).append("',null,'测试课程").append(i).append("',null)");
		//System.out.println("-----------------sb="+sb1);

		stmt.executeUpdate(sb1.toString());
	}
	
	conn.commit();

	stmt.close();		
	conn.close();
%>


tomcat 6启动后占用168M内存,
开始用proxool从100万-300万插入200万数据,tomcat6 占用内存从168M一直涨到1G,在插入完毕后,通过jrmc手动垃圾回收后,通过jrmc观察,时间堆的占用量还在600M左右,怎么也回收不了。

用dbcp从300万-500万插入200万数据,tomcat6 占用内存从168M稍微涨了一点,但是内存变化不大。

用c3p0从500万-700万插入200万数据,tomcat6 占用内存基本没有什么变化。

具体插入的时间我没有太多统计。粗略感觉,好像时间差不多

今天凌晨,服务器上2个tomcat中一个连接池切换成dbcp,到现在内存回收正常,一直很稳定,通过jrmc看内存占用一直稳定在40%左右,在到60%时会回收到40%,最低能回收到30%。

而另外一个依旧用proxool连接池的tomcat,内存占用率从40%一会就升到100%,然后突然回收到40%,然后一会有迅速的达到100%,然后又回收..........,最低只能回收到40%

在线监控中.......

不知道proxool是不是确实有内存泄露...........


-
分享到:
评论
20 楼 dreamlakyxy 2008-12-12  
congjl2002 写道
我的系统中也有内存泄漏的问题,但是现在没时间好好查,不过有一次我用jprofer简单查了一下,发现String这个占用内存很大,你是这样的吗?为什么呢

恩,对的。
附图:


19 楼 leoyu 2008-12-12  
LZ别遇到问题就怪人家内存泄露....这太损了...我想应该是你的配置不当造成的!我们一直用proxool
18 楼 allreturn 2008-12-12  
高手确实蛮多,  内在泄漏 确实是个大问题.
17 楼 skzr.org 2008-12-12  
无论是sun、ibm还是eclipse的编译器,全都会自动生成StringBuilder和append,和手工写的是完全一样的

这一点不敢同意:并不是sun、ibm、和eclipse的编译器了

我只为这个问题研究过手写StringBuilder的append和+ 在sun的JDK 5.0中生成的字节码 得出来实际上最后生成的直接码两者完全一致。并不是编译器的原因了
16 楼 congjl2002 2008-12-12  
我的系统中也有内存泄漏的问题,但是现在没时间好好查,不过有一次我用jprofer简单查了一下,发现String这个占用内存很大,你是这样的吗?为什么呢
15 楼 dreamlakyxy 2008-12-12  
javaeyebird 写道
dreamlakyxy 写道

StringBuilder sb1=new StringBuilder(sb);
sb1.append(i).append("','userId").append(i).append("','userName").append(i).append("',null,'测试课程").append(i).append("',null)");


插一个题外话:
根本不需要这样用StringBuilder,只要+就好了:
sb + i + "','userId" + i + "','userName" + ....
无论是sun、ibm还是eclipse的编译器,全都会自动生成StringBuilder和append,和手工写的是完全一样的
而+比append清晰多了

StringBuilder的一个适用场合是:用+需要生成中间字符串的时候,用StringBuilder替代:
StringBuilder sb = new StringBuilder();
for (...)
  sb.append(....);
sb.toString();

这样是比:
String s = "";
for (...)
  s += ...;

快的多,因为后面这个代码会生成很多字符串

那种只要有多个+就用StringBuilder替换的方式早就过时了,我们得与时俱进嘛,根据合适情况才替换


呵呵,谢谢谢谢,看样子我的知识库确实有点过时了,:)又多学了一招
14 楼 javaeyebird 2008-12-12  
dreamlakyxy 写道

StringBuilder sb1=new StringBuilder(sb);
sb1.append(i).append("','userId").append(i).append("','userName").append(i).append("',null,'测试课程").append(i).append("',null)");


插一个题外话:
根本不需要这样用StringBuilder,只要+就好了:
sb + i + "','userId" + i + "','userName" + ....
无论是sun、ibm还是eclipse的编译器,全都会自动生成StringBuilder和append,和手工写的是完全一样的
而+比append清晰多了

StringBuilder的一个适用场合是:用+需要生成中间字符串的时候,用StringBuilder替代:
StringBuilder sb = new StringBuilder();
for (...)
  sb.append(....);
sb.toString();

这样是比:
String s = "";
for (...)
  s += ...;

快的多,因为后面这个代码会生成很多字符串

那种只要有多个+就用StringBuilder替换的方式早就过时了,我们得与时俱进嘛,根据合适情况才替换
13 楼 puroc 2008-12-11  
dreamlakyxy 写道
sdh5724 写道
内存泄露你不用工具去检查, 光靠怀疑? 楼主似乎这么的做法太不科学了。 另外, JAVA的内存收集机制本来就是内存用的差不多才开始收集的。  你现在要做的是, 把在运行的JAVA进程, 使用jmap把堆dump下来, 找个内存heap分析工具, 看看是什么对象泄露了。 有很多免费的工具, 不过, 比较容易找到的, 免费的是 eclipse.org一个项目,可以独立运行, 也可以作为eclise的插件使用----MAT。 你去看看吧。

说得不错,老实说,程序问题,我已经用jprofiler测试了两个月了。我是这样测试的,走任何一个单独的功能前,把所有的自己编写的程序的类实例数目保存一遍,执行程序后,又把新的实例数和之前的实例数对比一遍,然后执行jprofiler自带手动垃圾回收,看看哪些实例不能垃圾回收。这样做,虽然工作量大,但是也检测出了一个地方的内存泄露,见我之前的帖子:http://www.iteye.com/topic/263300
经过严查,没有查出程序中存在的问题,然后把spring,hibernate,apache等常用的jar包全部更新的成最新的,内存泄露程序依然存在.........

这次分析出proxool存在问题,并不代表proxool确实存在问题,因为没有看它的源代码来分析,但是对于我来说,是不敢用这个连接池了


sdh5724如果对内存泄露比较熟悉,可以加我id,以后多探讨探讨


你测试内存泄漏的方法是对的。首先你要确保你在JProfile里面显示实例数量的那个视图中,设置的过滤条件是对的,会不会恰巧把存在内存泄漏的对象给过滤掉了,导致你没有发现。会不会你设置的过滤条件只是针对连接池的那些类,或者只是针对你自己写的那些代码。而其他的第三方包和JDK的实例没有观察到。如果过滤条件设置的没有问题,那么你使用这种方法没有检查出内存泄漏,那可能就是由于其他原因导致的。你可以观察一下你的程序使用的线程数,不知道你们是在什么操作系统上运行的,如果是solaris的话,用prstat观察一下你的进程,NLWP代表该进程使用的线程数,看看这个值在系统刚启动运行不久时是多少,然后再看看出现内存占用率比较高的时候是多少。如果增长了很多,那么可能是由于这个原因引起的。我们之前遇过一次类似的问题,就是由于线程创建过多导致的。
12 楼 qingshan 2008-12-11  
2M statements想一次就commit,想没问题也难啊。修改一下程序再测试吧!
11 楼 xucons 2008-12-11  
很有可能是THREAD LOCAL引起的,要注意threadlocal的使用要清空。
10 楼 dreamlakyxy 2008-12-11  
qingshan 写道
这个问题,先从自己程序找原因,去找其他什么连接池都没用。你把auto commit设置为false,那至少执行一定数量的statement(比如说100个)就应该commit一下。

这只是个测试程序!虽然效率不高,但是只执行一遍的话,程序本身不应该引起内存泄露问题吧?


实际的程序采用appfuse1.9的框架,struts1.2+spring2.5+hibernate3,
牵涉到数据库部分只用了hibernateTemplate和jdbcTemplate

系统到现在运行快一天了,好像两个tomcat的内存都上去了。看样子用dbcp也没用,内存泄露不是连接池的问题了。

有没有可能是线程影响的呢?程序中使用了不少Threadlocal
9 楼 ThinkingInAll 2008-12-11  
c3p0把
我们公司测过,没问题
8 楼 qingshan 2008-12-11  
这个问题,先从自己程序找原因,去找其他什么连接池都没用。你把auto commit设置为false,那至少执行一定数量的statement(比如说100个)就应该commit一下。
7 楼 sdh5724 2008-12-11  
c3p0吧, 我还是觉得这个最信的过,目前, 经过我们几个星期的连续烧烤,与几年的经验, 基本没有问题。 

关于内存问题, JAVA中可以被泄露的问题确实不多, 所以 比起C/C++的排查容易多了, 对于java heap, 你可以使用jmap 直接从生产环境拿下来内leak 分析, 如果很大的内存泄露, 看一眼就知道哪个对象泄露了。

连接POOL的泄露主要表现在, 使用的连接没有归还。要么是已经断开的连接没有释放。 HEAP分析工具对付这些问题切菜才一样。 另外, HEAP 在 DUMP出来的时候, 非live对象可以被排除的, 你看到的结果就是一个干净的, 被引用的对象。
6 楼 dreamlakyxy 2008-12-11  
lijunjie 写道
proxool这个连接池还是不错的.我一直用了好几个项目.应该比dbcp强.这个不一定是proxool连接池的问题.你可以换换数据库驱动版本试试.有时候连接池的某个版本跟数据库驱动的某个版本好像是存在问题.


我用的mysql官方最新的数据库驱动,同样的驱动,同样的程序,就是proxool有问题,其他两个连接池,确实内存两没怎么上升。

大家有时间的话,也可以测试一下
5 楼 dreamlakyxy 2008-12-11  
sdh5724 写道
内存泄露你不用工具去检查, 光靠怀疑? 楼主似乎这么的做法太不科学了。 另外, JAVA的内存收集机制本来就是内存用的差不多才开始收集的。  你现在要做的是, 把在运行的JAVA进程, 使用jmap把堆dump下来, 找个内存heap分析工具, 看看是什么对象泄露了。 有很多免费的工具, 不过, 比较容易找到的, 免费的是 eclipse.org一个项目,可以独立运行, 也可以作为eclise的插件使用----MAT。 你去看看吧。

说得不错,老实说,程序问题,我已经用jprofiler测试了两个月了。我是这样测试的,走任何一个单独的功能前,把所有的自己编写的程序的类实例数目保存一遍,执行程序后,又把新的实例数和之前的实例数对比一遍,然后执行jprofiler自带手动垃圾回收,看看哪些实例不能垃圾回收。这样做,虽然工作量大,但是也检测出了一个地方的内存泄露,见我之前的帖子:http://www.iteye.com/topic/263300
经过严查,没有查出程序中存在的问题,然后把spring,hibernate,apache等常用的jar包全部更新的成最新的,内存泄露程序依然存在.........

这次分析出proxool存在问题,并不代表proxool确实存在问题,因为没有看它的源代码来分析,但是对于我来说,是不敢用这个连接池了


sdh5724如果对内存泄露比较熟悉,可以加我id,以后多探讨探讨
4 楼 lijunjie 2008-12-11  
proxool这个连接池还是不错的.我一直用了好几个项目.应该比dbcp强.这个不一定是proxool连接池的问题.你可以换换数据库驱动版本试试.有时候连接池的某个版本跟数据库驱动的某个版本好像是存在问题.
3 楼 sdh5724 2008-12-11  
内存泄露你不用工具去检查, 光靠怀疑? 楼主似乎这么的做法太不科学了。 另外, JAVA的内存收集机制本来就是内存用的差不多才开始收集的。  你现在要做的是, 把在运行的JAVA进程, 使用jmap把堆dump下来, 找个内存heap分析工具, 看看是什么对象泄露了。 有很多免费的工具, 不过, 比较容易找到的, 免费的是 eclipse.org一个项目,可以独立运行, 也可以作为eclise的插件使用----MAT。 你去看看吧。
2 楼 dreamlakyxy 2008-12-11  
主要是为了测试连接池的性能,jsp程序当时没怎么考虑优化。:)
1 楼 fjlyxx 2008-12-11  
stmt.executeUpdate(sb1.toString()); 

用批量吧?这样提交成本太高了。个人经验批量提交的条数不要太多。多了数据库可能受不了。ORACLE 几万条提交一下还是很快的,MYSQL就慢多了。

相关推荐

    proxool-0.9.1.jar,proxool-cglib.jar

    标题中的"proxool-0.9.1.jar"和"proxool-cglib.jar"是两个重要的Java档案文件,它们是Proxool项目的组件。Proxool是一个开源的数据库连接池解决方案,它允许开发者在Java应用程序中高效地管理数据库连接。数据库连接...

    proxool-0.9.0RC3

    **proxool-0.9.0RC3:一个高效开源的数据库连接池** 在IT行业中,数据库连接池是提升应用程序性能的重要工具。其中,`proxool`是一个备受开发者青睐的开源连接池解决方案,版本号为0.9.0RC3。这个版本提供了稳定且...

    proxool-0.9.1.jar

    `proxool-0.9.1.jar` 是一个Java库,它提供了名为Proxool的数据库连接池服务。数据库连接池在多用户、高并发的Web应用中扮演着重要角色,因为它有效地管理了数据库连接,避免了频繁创建和关闭连接带来的性能开销。...

    proxool.jar包,proxool连接池用到的两个jar包

    `proxool.jar`是Proxool数据库连接池的实现库,它是Apache软件基金会的一个开源项目。Proxool是一个轻量级、高效的数据库连接池解决方案,它允许开发者在Java应用程序中管理数据库连接,以提高性能并减少资源消耗。...

    Proxool.jar

    同时,监控Proxool的运行状态,定期检查日志,以便及时发现并解决可能出现的连接泄漏或资源耗尽问题。 在压缩包的`lib`目录下,如果没有其他文件,那么可能假设开发者已经将所有必要的库文件都包含在项目中。通常,...

    proxool配置详解

    标题中的“proxool配置详解”指的是Proxool,这是一个开源的数据库连接池管理工具,它在Java应用程序中用于管理和优化数据库连接。Proxool的主要作用是提高应用性能,通过复用已建立的数据库连接,避免频繁创建和...

    proxool连接池jar包

    3. **监控功能**:独特的监控机制使得开发者可以实时查看连接池的状态,如当前连接数、空闲连接数、等待连接数等,这有助于及时发现并解决连接泄漏问题。 4. **诊断能力**:当系统出现异常时,Proxool能提供详细的...

    Hibernate+Proxool配置

    由于项目需求的需要,我们引入了连接池。...我们采用了Hibernate,所以可以考虑hibernate自带的连接池机制,但是发现效率不高,而且Hibernate也推荐使用c3p0或Proxool连接池,在我们的项目中采用了Proxool

    Proxool-0.9.1

    1.解决不能Unregister jdbc driver的内存泄露问题。 十二月 02, 2013 8:19:43 上午 org.apache.catalina.loader.WebappClassLoader clearReferencesJdbc SEVERE: The web application [/xxx] registered the JDBC ...

    proxool_0.9.1

    标题“proxool_0.9.1”提及的是一个名为Proxool的数据库连接池管理工具的特定版本,即0.9.1。Proxool是Apache软件基金会的一个开源项目,它提供了一种轻量级的数据库连接池解决方案,允许开发者更有效地管理和控制...

    proxool相关jar包.rar

    总结来说,"proxool相关jar包.rar"提供的是一组用于管理数据库连接的Java类库,包括Proxool的两个不同版本和其依赖的CGLIB库。这些资源可以帮助开发者构建高效、可监控的数据库连接池,提升Java应用的性能和稳定性。

    proxool 数据库

    **Proxool数据库连接池详解** 在IT行业中,数据库管理是关键的一环,尤其是在高并发、大数据量的应用场景下,数据库连接池的使用显得尤为重要。Proxool是Apache的一个开源项目,它提供了一个轻量级的数据库连接池...

    proxool配置

    这样不仅减少了数据库连接的创建和销毁开销,还能防止过多连接导致的资源耗尽问题。 **配置Proxool** 1. **添加依赖**: 首先,你需要在项目中引入Proxool的库。如果你使用的是Maven,可以在pom.xml文件中添加以下...

    proxool连接池

    **Proxool 连接池详解** Proxool 是一个高效、易用的数据库连接池,它通过提供中间代理层管理数据库连接,从而实现数据库连接的复用,提高应用程序的性能和效率。Proxool 的设计目标是为 Java 应用程序提供简单、...

    proxool链接池

    **Proxool连接池详解** Proxool是Apache软件基金会的一个开源项目,它是一个轻量级的数据库连接池实现,提供了高效、灵活的数据库连接管理。在Java应用程序中,使用数据库连接池可以显著提高数据库操作的性能,因为...

    Proxool api chm

    Java connection pool : Proxool api(chm)

    proxool-0.9.0RC3.jar

    "proxool-0.9.0RC3.jar" 是一个Java档案文件,它包含了Proxool库的0.9.0RC3版本。Proxool是开源的Java连接池实现,设计用于提供数据库连接管理服务,它使得在多线程环境中高效地管理和重用数据库连接成为可能。连接...

    proxool-0.9.1 jar;proxool-cglib.jar;

    压缩包子文件的文件名称列表只提到了"proxool",这可能意味着除了这两个JAR文件外,可能还需要其他依赖库或配置文件才能完整运行Proxool。 总结来说,Proxool是一个功能强大且易于使用的Java数据连接池实现,通过...

    proxool.jar

    **Proxool数据库连接池详解** Proxool是源自SourceForge的一个开源项目,它是一款针对Java平台设计的高效、易用的数据库连接池技术。在Java应用开发中,数据库连接池是一个至关重要的组件,用于管理和复用数据库...

    java连接池proxool

    Java连接池,特别是Proxool,是数据库管理中一个至关重要的概念,它提高了数据库操作的效率和性能。连接池在Java应用程序中起着桥梁的作用,它管理数据库连接,避免了频繁创建和销毁连接的开销。Proxool是Apache软件...

Global site tag (gtag.js) - Google Analytics