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

困扰了近两月的内存泄露问题终于初见眉目了,罪魁祸首: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是不是确实有内存泄露...........


-
分享到:
评论
40 楼 airport 2009-01-19  
proxool 好像是我比较三个连接池后选用的最好的一个。

要是本身有问题,不至于现在才发现。
39 楼 lzb7213 2009-01-15  
sdh5724 写道
c3p0吧, 我还是觉得这个最信的过,目前, 经过我们几个星期的连续烧烤,与几年的经验, 基本没有问题。 

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

连接POOL的泄露主要表现在, 使用的连接没有归还。要么是已经断开的连接没有释放。 HEAP分析工具对付这些问题切菜才一样。 另外, HEAP 在 DUMP出来的时候, 非live对象可以被排除的, 你看到的结果就是一个干净的, 被引用的对象。

C3P0 不行 你可以google下 对连接的释放速度跟不上 对于并发数量很多的系统就不行 一般系统还是可以的  proxool对连接的管理还是可以的 在大并发量下 对连接的管理很好
38 楼 dreamlakyxy 2008-12-18  
sg552 写道
dreamlakyxy 写道
困扰了近两月的内存泄露问题终于初见眉目了,罪魁祸首:proxool

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

-


能否说说你是如何使用JProfiler的??

按照我的经验,它是最擅长查这个的。


jrmc我用的也不是特别熟。

就是通过jrmc的console和memleak检查的,通过console检查内存,线程,cpu的使用状况,通过memleak检查类实例和说占用的heap的大小,没过一段时间,检查一些,哪些类实例增加的特别大,就右键选择,进行堆栈分配跟踪

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


可能是taglib问题: http://xsen.iteye.com/blog/159218



我把http://xsen.iteye.com/blog/159218的原文引过来了了
引用

最近遇到了Java系统内存泄漏的问题,翻了几遍代码也没看出来问题来。最后怀疑是开源控件的问题,首先想到了Quartz,但最终也没发现太多问题。也看过JProfiler监控的情况,除了String对象占用内存较多以外,也没发现任何其他异常数量的对象。
最后还是老大用jmap和jhat查出了问题,罪魁祸首是taglib,因为我们的页面中使用了taglib,而传入的值是一个拼接了当前时间数的字符串(一个url),而taglib对这些变量有缓存功能,所以每次页面请求taglib都会缓存一个url字符串。具体是放在一个Map类型的静态变量中的,所以当系统运行3天左右内存就爆满了。。。


我也是发现String占用量特别大,经过memleak检查,是发现taglib占用了很多,但是没想到原因。我们也是每个url+一个当前时间的字符串,难道这个影响?

那怎么改呢,很多情况下,如果不拼时间字符串的话,都会缓存的

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


可能是taglib问题: http://xsen.iteye.com/blog/159218
35 楼 sg552 2008-12-17  
dreamlakyxy 写道
困扰了近两月的内存泄露问题终于初见眉目了,罪魁祸首:proxool

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

-


能否说说你是如何使用JProfiler的??

按照我的经验,它是最擅长查这个的。
34 楼 dreamlakyxy 2008-12-16  
robbin 写道
dreamlakyxy 写道
解决方案有:
1. nginx采用ip_hash,同一个ip段,定位到同一个tomcat上,
2. 禁用session。
但是我把公共引用的jsp页面设置了 <%@ page session="false" %> ,好像还是能生成session。

现在准备采用HttpSessionListner,一生成session,就把他销毁。

不知道大家还有没有更好的办法,来完全禁用session。tomcat有配置完全禁用session的地方吗?


web.xml里面可以设置session过期时间,你可以把过期时间改成1分钟试试看。

恩,也是一种方法
33 楼 robbin 2008-12-16  
dreamlakyxy 写道
解决方案有:
1. nginx采用ip_hash,同一个ip段,定位到同一个tomcat上,
2. 禁用session。
但是我把公共引用的jsp页面设置了 <%@ page session="false" %> ,好像还是能生成session。

现在准备采用HttpSessionListner,一生成session,就把他销毁。

不知道大家还有没有更好的办法,来完全禁用session。tomcat有配置完全禁用session的地方吗?


web.xml里面可以设置session过期时间,你可以把过期时间改成1分钟试试看。
32 楼 dreamlakyxy 2008-12-16  
解决方案有:
1. nginx采用ip_hash,同一个ip段,定位到同一个tomcat上,
2. 禁用session。
但是我把公共引用的jsp页面设置了 <%@ page session="false" %> ,好像还是能生成session。

现在准备采用HttpSessionListner,一生成session,就把他销毁。

不知道大家还有没有更好的办法,来完全禁用session。tomcat有配置完全禁用session的地方吗?
31 楼 dreamlakyxy 2008-12-16  
经分析,session确实可能引起问题。我们程序完全没有用session,也没用关闭session。
一个nginx随机分发到两个tomcat上面,

假设一个极端的情况下,一个用户一个小时,点击了200万个不同的页面,每次通过nginx分发到不同tomcat上,
T1(tomcat1),T2(tomcat2),收到url的顺序是t1,t2,t1,t2,t1,t2 ..........

1. t1判断是New url,生成一个session,同时置sessionid与客户端的会话cookie中
2. t2判断是New url,同时判断客户端会话cookie的中的sessionid,不是t2自己生成的id,于是生成一个新session,同时置sessionid与客户端的会话cookie中
3. t1收到url,同时判断客户端会话cookie的中的sessionid,不是t1自己生成的id,于是生成一个新session,同时置sessionid与客户端的会话cookie中
.
.
.

所以在一个小时内,t1,t2分别生成了100万个session,如果session的默认过期时间为1个小时,则,这个100万个session都存在内存中.


所以session应该是其中的一个原因,但还不是关键原因。
30 楼 dreamlakyxy 2008-12-15  
nickxu 写道
xucons 写道
很有可能是THREAD LOCAL引起的,要注意threadlocal的使用要清空。

我想问一下ThreadLocal的内容不是线程结束后自动被jvm回收吗?需要手动清空?

我查了一下,好像不需要的
29 楼 nickxu 2008-12-15  
xucons 写道
很有可能是THREAD LOCAL引起的,要注意threadlocal的使用要清空。

我想问一下ThreadLocal的内容不是线程结束后自动被jvm回收吗?需要手动清空?
28 楼 puroc 2008-12-14  
既然proxool的问题,就还他个清白吧。改一下帖子的标题吧。他醒目了。
27 楼 javaeyebird 2008-12-12  
skzr.org 写道
无论是sun、ibm还是eclipse的编译器,全都会自动生成StringBuilder和append,和手工写的是完全一样的

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

我只为这个问题研究过手写StringBuilder的append和+ 在sun的JDK 5.0中生成的字节码 得出来实际上最后生成的直接码两者完全一致。并不是编译器的原因了

生成字节码就是编译器的事啊

这三家的编译器javac(就是.java->.class)我都仔细验证过字节码
字符串+都是得到调用StringBuilder.append的字节码,而不是调用String.concat
26 楼 dreamlakyxy 2008-12-12  
到现在为止,又平稳的运行一天了。
通过jrmc查看:
tomcat1 线程数66,没有死锁,
tomcat2 线程数70,没有死锁
25 楼 dreamlakyxy 2008-12-12  
robbin 写道
等Tomcat内存泄漏现象明显的时候 kill -3 pid
等tomcat已经死掉的时候先不要着急重起,再次kill -3 pid

让他dump整个线程堆栈,看看有没有大量被BLOCKED状态的线程,观察一下线程状态。


恩,我试试。

刚才分析堆栈,图片如下:



发现可能tomcat session创建了很多ConcurrentHashMap实例,难道竟然是session影响?

我们程序是不用session的,准备在common.jsp中加上 <%@ page session="false" %>

刚刚看了一个帖子,觉得很有理,大家以为然否?
http://sdyouyun.iteye.com/blog/146275


24 楼 robbin 2008-12-12  
等Tomcat内存泄漏现象明显的时候 kill -3 pid
等tomcat已经死掉的时候先不要着急重起,再次kill -3 pid

让他dump整个线程堆栈,看看有没有大量被BLOCKED状态的线程,观察一下线程状态。
23 楼 dreamlakyxy 2008-12-12  
事务配置如下:
<bean id="txProxyTemplate" abstract="true"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="transactionManager" ref="transactionManager" />
		<property name="transactionAttributes">
			<props>
				<prop key="save*">PROPAGATION_REQUIRED</prop>
				<prop key="update*">PROPAGATION_REQUIRED</prop>
				<prop key="delete*">PROPAGATION_REQUIRED</prop>
				<prop key="remove*">PROPAGATION_REQUIRED</prop>
				<prop key="add*">PROPAGATION_REQUIRED</prop>
				<prop key="modify*">PROPAGATION_REQUIRED</prop>
				<prop key="calculate*">PROPAGATION_REQUIRED</prop>
				<prop key="process*">PROPAGATION_REQUIRED</prop>
				<prop key="noTransaction*">PROPAGATION_NOT_SUPPORTED</prop>
				<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
			</props>
		</property>
	</bean>


然后所有的manager bean的配置都是类似下面的代码
<bean id="forumAreaManager" parent="txProxyTemplate">
		<property name="target">
			<bean
				class="com.fjt.forum.service.impl.ForumAreaManagerImpl">
				<property name="forumAreaDao" ref="forumAreaDao" />
				<property name="commonTagDao" ref="commonTagDao" />
			</bean>
		</property>
	</bean>


服务器宕机的时的表现是,两个tomcat的java进程所占cpu都是400%左右,用linux top命令看的。
这个时候把catalina.out日志备份后删除,重启tomcat。
事后分析catalina.out日志,发现没有什么特殊的地方,没有不能创建mysql连接、connection消耗尽的情况,都是常规的日志。其中关于jrockit垃圾回收的日志有下面几条
[INFO ][memory ] 35315.048-35332.522: GC 611536K->512771K (920128K), sum of pauses 183.922 ms
***其他的正常日志

[INFO ][memory ] 35359.423: parallel nursery GC 902118K->454118K (920128K), 1766.494 ms
***其他的正常日志

[INFO ][memory ] 35470.454: parallel nursery GC 902118K->511718K (920128K), 3117.067 ms
***其他的正常日志


22 楼 dreamlakyxy 2008-12-12  
robbin 写道
看起来ConcurrentHashMap对象实例的数量格外的高。你应该检查一下应用程序在什么地方大量用到了这个类。推荐你看看:

http://www.iteye.com/post/676536
http://www.iteye.com/topic/231670

这两个帖子提到在高并发情况下ConcurrentHashMap的锁定问题,有可能是Spring事务配置不合理导致的。


恩,我研究研究这两个帖子。

首先可以肯定是,自己编写的程序没有直接用到过ConcurrentHashMap。
可能用到ConcurrentHashMap的地方,也许是spring,hibernate等类库。
我检查检查

robbin大侠出手了,谢谢谢谢。

21 楼 robbin 2008-12-12  
看起来ConcurrentHashMap对象实例的数量格外的高。你应该检查一下应用程序在什么地方大量用到了这个类。推荐你看看:

http://www.iteye.com/post/676536
http://www.iteye.com/topic/231670

这两个帖子提到在高并发情况下ConcurrentHashMap的锁定问题,有可能是Spring事务配置不合理导致的。

相关推荐

Global site tag (gtag.js) - Google Analytics