tomcat的运行的时候,GC进行内存回收,回收后的内存是还给OS还是还给JVM

07-03-18 luolaluola
为什么用jprofilter监视器得到的堆使用情况呈现一定的频率,堆示图显示规则锯齿状。一开始任务管理器显示所有进程内存500多m,过了一会儿任务管理器显示的内存使用数一直在增加,而任务管理器显示tomcat的内存保持在380m,但是系统所有进程内存已经1000多m,5~6个小时后之后系统提示虚拟内存不足,tomcat档掉!

服务器硬件环境:内存:512m,cpu P42.8双核
os:window server2003, database:sqlserver2000 (sp4)
tomcat5.5(-Xms128m -Xmx392m)

服务器监视器:JPROFILTER

客户端测试工具:jemter2.2 开一个线程组 里面有个80个线程,每隔4秒启动80个线程,也就是每个线程之间的间隔是4/80,http请求数10个



luolaluola
2007-03-18 16:33
补充一下,在系统还有显示虚拟内存之前,一直很稳定~~~ 速度很快,我通过jmeter查看到 平均值:2300-3050之间,偏离:1700左右

[该贴被bingochen于2007年03月18日 16:49修改过]

[该贴被bingochen于2007年03月18日 16:51修改过]

banq
2007-03-19 10:26
>5~6个小时后之后系统提示虚拟内存不足,tomcat档掉!
这表示你的应用程序存在内存泄漏,就是JVM垃圾回收机制无法回收你的对象了,需要全面check你的程序,可以通过JPROFILTER定位哪个类占用内存最多,问题就可能出在那里。

相关理论讨论:
jsp+javabean能否满足同时100人使用?

http://www.jdon.com/article/30437.html

aa123456789
2007-03-19 11:13
测试

[该贴被aa123456789于2007年03月19日 11:14修改过]

Coolyu0916
2007-03-19 12:05
可以参考一下gc的收取规则
通常来说约晚分配的内存越早回收,也就是尽量减少引用的次数,引用了之后就没不能立即回收了。

luolaluola
2007-03-19 13:25
哦,可能是这个原因,我的测试代码思路是这样的,

从连接池中取得连接,通过调用存储过程,查询返回ResultSet 然后通过ResultSetMetaData.getColumnCount()取得Column的长度,通过长度建立String[],一个数据行是一个String[],循环读取ResultSet,把数据行写入String[],然后把String[]写入Arraylist<String[]>,最后释放Conn,Statement,ResultSet 然后返回ArrayList,把返回的rrayList值提交给一个xml生成类,生成xml类,把ArrauList clear()掉,然后输出xml, 当并发量大的话,循环建立 new String[] 可能会耗资源

luolaluola
2007-03-19 14:08
依照上面的方式,我发现往ArrayList里面加String[]对象,当ArrayList做clear() 和 付NULL操作时,String[]对象并没有被释放,不知道是不是这个原因引起的

Coolyu0916
2007-03-19 20:49
不明白为什么要先写入ArrayList然后再变成xmldoc那??
不能从Result直接变么??

luolaluola
2007-03-19 21:22
按照banq的意思 用了jprofilter进行跟踪 发现一个对象占用太多内存,而且实例数超多,一直增加 一次增加几百个实例

com.microsoft.jdbc.vprt.SSLexTableRowEntry 这个类 不知道什么原因,谁能提供些资料

Coolyu0916
2007-03-19 21:31
最后释放Conn,Statement,ResultSet ??
是不是顺序反了??

luolaluola
2007-03-19 21:39
先释放resultset 然后释放CallableStatement,最后释放connection

banq
2007-03-21 09:03
前面的ArrayList确认是否释放了,是否执行clear了,需要通过记录跟踪,还要确定clear的ArrayList是否就是塞入String[]的ArrayList

关于>SSLexTableRowEntry
很可能是连接没有释放,打开数据库连接和关闭连接必须在一个方法中完成,这样才安全,不能跨方法,关闭连接是否是在finally语句中.

是否使用数据库连接池?怎样使用的?是使用容器服务器自己的连接池,还是第三方,如果是第三方,是否经过成熟应用.

是否JDBC事务设置不正确,JDBC有四个事务隔离级别,READ_UNCOM READ_COM等,Oracle缺省的是READ_COM,所以Oracle很少有数据库连接死锁现象,SQL-server缺省不是很清楚,估计和sysbase一样是第三个事务隔离,虽然安全,但是会发生死锁,甚至内存泄漏.

确认以上问题,特别是最后一个问题,比较烦琐,需要花时间学习或接受培训一下.

luolaluola
2007-03-21 11:30
感谢BNAQ的关注 ^_^

我现在找到问题的根源了,问题根源在于连接池设置,业务过程不存在内存泄漏。原先采用proxool连接池 最大连接数1000个最小连接数200个 其他的选项都是默认的设置,ResultSet CallableStatement,Connnect 都有及时释放(Connnect只是放回连接池) 但是这种情况显示,当并发量大的话 GC内存回收 速度极慢 com.microsoft.jdbc.vprt.SSLexTableRowEntry 这个实例数都达到几百万上千万,而且释放速度比增加速度少几十甚至上百倍,而jvm的内存设置是(-Xms128m -Xmx392m),远远不够的,当内存严重不足的情况下,GC开始进行回收有几次完整的回收但是 一些旧的对象根本就无法回收,最后崩溃。

在后来的测试中配置:最大连接数100,最小连接数10 个 jmeter 5个线程,1秒钟并发一次,根据jropfilter的显示不管是 gc时间还是堆视图 可以看到 整个回收非常完整彻底....


是否使用数据库连接池?怎样使用的?是使用容器服务器自己的连接池,还是第三方,如果是第三方,是否经过成熟应用.


-----------------------------------------------------------------
Banq:是否JDBC事务设置不正确,JDBC有四个事务隔离级别,READ_UNCOM READ_COM等,Oracle缺省的是READ_COM,所以Oracle很少有数据库连接死锁现象,SQL-server缺省不是很清楚,估计和sysbase一样是第三个事务隔离,虽然安全,但是会发生死锁,甚至内存泄漏.

请问banq老师 哪里可以得到你提到的JDBC事务这方面的资料,还有有没有那种最佳内存方案的资料 谢谢


banq
2007-03-22 08:44
>在找到问题的根源了,问题根源在于连接池设置,业务过程不存在内存泄漏

我觉得这可能不是真正原因, 因为如果并发量一大,我们的服务器就崩溃,这显然不能算一个成熟的系统.

正常情况是:当并发量大时,如果我们控制资源,这样就是jmeter发出10个并发线程请求,但是我们的系统只并发处理5个并发线程请求,其他请求必须等待,最后良好结果应该是:无论多大并发量,服务器正常运行,只有jmeter一些线程请求响应时间很长.

虽然你将连接池设置改动了,这也是控制资源的一部分,但是效果不大,因为这是后端,多余并发请求已经从前端(jsp/servlet)进入到了你的服务器中了,而且已经启动了最耗内存的业务Bean,尽管你在通往数据库的路上进行了限制,这只会让问题更遭.

另外, 你的测试条件"jmeter 5个线程,1秒钟并发一次"测试条件太松,JdonFramework测试是8个线程,0秒钟一次,也就是8个线程同时发出,这才能模拟同时同用户操作的环境.

"JDBC事务这方面的资料"一般都在数据库的JDBC章节有说明,"最佳内存方案"我认为就是不要以数据库为中心设计,将分散的数据使用业务对象封装起来,使用Cache和Pool,提高内存击中率,减少数据库连接池的使用,使用Pool或单态控制并发高峰对服务器的伤害.这些原理在我设计的JdonFramework时都考虑到,封装在框架中,不让每个应用都为这个问题专门考虑设计.


[该贴被banq于2007年03月22日 09:00修改过]

[该贴被banq于2007年03月22日 09:01修改过]

[该贴被banq于2007年03月22日 09:04修改过]

luolaluola
2007-03-22 10:49
谢谢BANQ,嗯,重点还是你说的将分散的数据使用业务对象封装起来,使用Cache和Pool,提高内存击中率。提高并控制内存击中率 这个实现起来就复杂了,如果要这么做,是不是要cache业务对象,做一个pool对象池,根据业务需要,调节pool中业务对象的个数以便于控制内存使用命中率和系统负荷,不过写这些东西估计做起来很复杂

我去看看JDONFRAME的实现先

2Go 1 2 下一页