JDK+apache+tomcat,网站运行一段时间内存变化太大
tomcat :凌晨二点至八点期间:从997MB降到260MB 每半个小时提取内存监控!2008-11-14 02:10:50.062:-------------create Connect----------
2008-11-14 02:10:53.015:maxMemory=1016MB; totalMemory=1016MB; freeMemory=997MB
2008-11-14 02:41:11.718:maxMemory=1016MB; totalMemory=1016MB; freeMemory=982MB
2008-11-14 02:41:14.703:maxMemory=1016MB; totalMemory=1016MB; freeMemory=980MB
2008-11-14 02:41:17.718:maxMemory=1016MB; totalMemory=1016MB; freeMemory=982MB
2008-11-14 02:41:19.000:maxMemory=1016MB; totalMemory=1016MB; freeMemory=982MB
2008-11-14 02:45:25.500:maxMemory=1016MB; totalMemory=1016MB; freeMemory=983MB
008-11-14 03:40:59.703:maxMemory=1016MB; totalMemory=1016MB; freeMemory=758MB
2008-11-14 03:41:21.140:maxMemory=1016MB; totalMemory=1016MB; freeMemory=755MB
2008-11-14 03:42:02.546:maxMemory=1016MB; totalMemory=1016MB; freeMemory=757MB
2008-11-14 04:41:04.171:maxMemory=1016MB; totalMemory=1016MB; freeMemory=616MB
2008-11-14 04:41:23.968:maxMemory=1016MB; totalMemory=1016MB; freeMemory=616MB
2008-11-14 04:41:45.156:maxMemory=1016MB; totalMemory=1016MB; freeMemory=617MB
2008-11-14 05:41:10.031:maxMemory=1016MB; totalMemory=1016MB; freeMemory=504MB
2008-11-14 05:41:28.953:maxMemory=1016MB; totalMemory=1016MB; freeMemory=502MB
2008-11-14 05:41:48.328:maxMemory=1016MB; totalMemory=1016MB; freeMemory=505MB
2008-11-14 06:41:16.968:maxMemory=1016MB; totalMemory=1016MB; freeMemory=401MB
2008-11-14 06:41:30.765:maxMemory=1016MB; totalMemory=1016MB; freeMemory=400MB
2008-11-14 06:41:40.015:maxMemory=1016MB; totalMemory=1016MB; freeMemory=397MB
2008-11-14 07:21:12.843:maxMemory=1016MB; totalMemory=1016MB; freeMemory=329MB
2008-11-14 07:21:29.781:maxMemory=1016MB; totalMemory=1016MB; freeMemory=326MB
2008-11-14 07:21:43.609:maxMemory=1016MB; totalMemory=1016MB; freeMemory=325MB
2008-11-14 07:21:53.031:maxMemory=1016MB; totalMemory=1016MB; freeMemory=325MB
2008-11-14 07:51:28.937:maxMemory=1016MB; totalMemory=1016MB; freeMemory=289MB
2008-11-14 07:51:57.593:maxMemory=1016MB; totalMemory=1016MB; freeMemory=290MB
2008-11-14 08:09:03.984:maxMemory=1016MB; totalMemory=1016MB; freeMemory=268MB
2008-11-14 08:09:42.281:maxMemory=1016MB; totalMemory=1016MB; freeMemory=268MB
2008-11-14 08:09:51.437:maxMemory=1016MB; totalMemory=1016MB; freeMemory=267MB
2008-11-14 08:09:55.984:maxMemory=1016MB; totalMemory=1016MB; freeMemory=267MB
2008-11-14 08:10:42.078:maxMemory=1016MB; totalMemory=1016MB; freeMemory=255MB
2008-11-14 08:10:42.078:maxMemory=1016MB; totalMemory=1016MB; freeMemory=255MB
2008-11-14 08:10:42.078:maxMemory=1016MB; totalMemory=1016MB; freeMemory=255MB
2008-11-14 08:11:15.000:maxMemory=1016MB; totalMemory=1016MB; freeMemory=260MB
2008-11-14 08:13:26.578:-------------create Connect---------- 内存泄漏检测工具
1.ccmalloc-Linux和Solaris下对C和C++程序的简单的使用内存泄漏和malloc调试库。
2.Dmalloc-Debug Malloc Library.
3.Electric Fence-Linux分发版中由Bruce Perens编写的malloc()调试库。
4.Leaky-Linux下检测内存泄漏的程序。
5.LeakTracer-Linux、Solaris和HP-UX下跟踪和分析C++程序中的内存泄漏。
6.MEMWATCH-由Johan Lindh编写,是一个开放源代码C语言内存错误检测工具,主要是通过gcc的precessor来进行。
7.Valgrind-Debugging and profiling Linux programs, aiming at programs written in C and C++.
8.KCachegrind-A visualization tool for the profiling data generated by Cachegrind and Calltree.
9.IBM Rational PurifyPlus-帮助开发人员查明C/C++、托管.NET、Java和VB6代码中的性能和可靠性错误。PurifyPlus 将内存错误和泄漏检测、应用程序性能描述、代码覆盖分析等功能组合在一个单一、完整的工具包中。
10.Parasoft Insure++-针对C/C++应用的运行时错误自动检测工具,它能够自动监测C/C++程序,发现其中存在着的内存破坏、内存泄漏、指针错误和I/O等错误。并通过使用一系列独特的技术(SCI技术和变异测试等),彻底的检查和测试我们的代码,精确定位错误的准确位置并给出详细的诊断信息。能作为Microsoft Visual C++的一个插件运行。
11.Compuware DevPartner for Visual C++ BoundsChecker Suite-为C++开发者设计的运行错误检测和调试工具软件。作为Microsoft Visual Studio和C++ 6.0的一个插件运行。
12.Electric Software GlowCode-包括内存泄漏检查,code profiler,函数调用跟踪等功能。给C++和.Net开发者提供完整的错误诊断,和运行时性能分析工具包。
13.Compuware DevPartner Java Edition-包含Java内存检测,代码覆盖率测试,代码性能测试,线程死锁,分布式应用等几大功能模块。
14.Quest JProbe-分析Java的内存泄漏。
15.ej-technologies JProfiler-一个全功能的Java剖析工具,专用于分析J2SE和J2EE应用程序。它把CPU、执行绪和内存的剖析组合在一个强大的应用中。JProfiler可提供许多IDE整合和应用服务器整合用途。JProfiler直觉式的GUI让你可以找到效能瓶颈、抓出内存泄漏、并解决执行绪的问题。4.3.2注册码:A-G666#76114F-1olm9mv1i5uuly#0126
16.BEA JRockit-用来诊断Java内存泄漏并指出根本原因,专门针对Intel平台并得到优化,能在Intel硬件上获得最高的性能。
附录:内存泄漏的发生方式
1.常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
2.偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
3.一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块且仅有一块内存发生泄漏。
4.隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。 术语说明:
IBM Websphere Application Server:WAS,WebSphere本身是一个平台,产品家族
OutOfMemoryError:OOM,内存泄漏,内存溢出
Gabage Collection:GC,自动垃圾回收
Content Management System:CMS,就是给新闻类门户网站编辑们用的系统
我们诊断大体上经历了以下几个阶段:
1、按Job调度线程池引起内存泄漏诊断:因为很多次OOM是发生在某个特定时候,譬如14:30、22:40左右。
2、按应用程序引起内存泄漏诊断:用JProfiler等工具探测:因为总是发生OOM。
3、分离WAS怀疑有OOM的应用:因为每个WAS应用太多,20来个,混一起没法定位。
4、用IBM官方heap、GC分析工具。以及和IBM技术支持联系。WAS、AIX参数优化。
5、隔离出WAS超级恶魔程序:一个CMS产品。
6、WAS、AIX参数优化、设置。
我们走到第5步时,才出现效果。计算一下,那时已经过去一个月了。服务器宕机、系统不稳定,在这个验收的时候,客户已经忍无可忍,以致后来的每一次行动都得胆战心惊得去做。
一、按Job调度线程池导致内存泄漏诊断
因为从我们WAS的日志(默认是native_stderr.log)来看,最近半年的宕机时间都有一个明显时间规律。见附件截图Job1-1.png。
我想,做过Java服务器性能调优的朋友,都知道在Web容器里面启线程池是个不太好的做法,因为Web容器本身有一个线程池,譬如Servlet线程池(Tomcat默认起25个),而自启的线程池很容易导致Servlet线程管理混乱,最终导致GC问题。我们的现象似乎和那很符合。如果我们沿着这个思路做下去,具体怎样实施呢?
我们的WAS上部署了20个左右的Web应用,譬如Lucene全文检索、B2B行业数据同步等,都是通过Quartz的Job调度做的,当然还有很多其它调度。当时,由我负责,通知相关负责人,将定时调度暂时去掉。观察了几天,后来发现问题依然存在,不过时间有点随机了。
不过,最后还是发现OOM不是由Job调度引起的。
也就是说,我们这个方案是失败的。而且,我们的很多想法都是臆测的,没有可靠的根据,也没有方向,再加上我是第一次处理这种问题,这导致后来查找问题的艰难。但是,仔细想想,我们又能拿什么做依据呢?出现OOM错误,我想大多数人想到的,除了JVM参数设置,就是内存泄漏。其实,OOM发生有很多种情况,在IBM、Sun、BEA等不同虚拟机上,因为GC机制不一样,所以原因一般都不同,容易定位难度也不一样。下文会谈到。
于是,我们干脆釜底抽薪分析问题吧:用JProfiler检测。
二、按应用程序导致内存泄漏诊断,JProfiler检测
如果遇到OOM问题,我想大家都会想到内存检测工具,现在最可靠的还是下面三种分析工具:Borland 的Optimizeit Suite,Quest的JProbe,ej-technologies的JProfiler。但面临三个问题:
1、三个都是商业产品,公司暂时没有买,必须自己下载,而且要找序列号。
2、工具必须支持AIX5.3+JDK1.42+WAS6.0,不是Windows平台。
3、工具必须在客户真实环境下部署,对客户的业务不能有冲击,也就是说部署测试工具前,必须做个大量测试,对工具非常熟练,遇到意外可以立即恢复现场。
Note:项目上线后,而不是测试或试运行阶段遇到此类问题,非常考验人;另外一个,就是性能和可伸缩性问题,很可能把整个项目给毁了。
当我决定要这么做后,就立即动手查阅这些工具的官方文档,用emule下载,最终都下载到了。试用后,最终选择了JProfiler4.03,比起其它工具,它界面美观、清晰、功能强大、集成度高(Heap,Memory,CPU,Thread都统一了)。另外,JProbe没有AIX版本,这也是放弃它的一个原因。
JVM的Profiler原理,都是通过JVM内置的的标准C语言Profiler 接口收集数据,然后通过Profiler工具的客户端展现。也就是说各厂商的Profiler工具,都有两个部分,一个部分是Profiler Agent,和JVM绑定,负责收集JVM内部数据,譬如方法调用次数、耗费时间等;另外一个部分就是Profiler front-end。通过Profiler工具的自定义local或remote协议传输到front-end,其实,我们最常用的JavaIDE的debug功能就是在此基础上的(JPDA)。(JProfiler的截图http://www.ej-technologies.com/products/jprofiler/screenshots.html )。
下面是Sun官方文档:
JDK1.42及以前是JVM PI:http://java.sun.com/j2se/1.4.2/docs/guide/jvmpi/jvmpi.html
JDK1.5是JVM TI:http://java.sun.com/j2se/1.5.0/docs/guide/jvmti/jvmti.html
具体到JProfiler的配置上,专门针对JDK1.4和1.5的JVM配置差别很大。
我用的JProfiler是4.31版本,透露给大家一个万能序列号吧(这东西不太好找),对各版本应该都支持。深入了解Java,这类工具是不可少的:
Name: License for You
Lincese Code: A-G667#42616F-10kg1r134fq9m#2217
为了保证真实环境的检测成功,我做了大量的试验,譬如:
1、Windows系列的本地、远程测试。
2、AIX的远程测试。
3、Tomcat5.0、WebLogic8.14、WebSphere6.02,以及上述两种方式的组合测试,排列组合,场景不下10个。
当时也参阅了大量JVM文档,JProfiler官方几百页英文文档,辅助的JProbe对照。而且也制造过内存泄漏造成的OOM场景。
当然,要是在几个月前,在客户那边部署的测试环境时,就进行测试该多好啊。
在公司内部,我用JProfiler测试了我们当时部署的几个应用,没有发现内存泄漏,所以,我们最怀疑的是就是CMS系统。因为出问题的那个WAS上它占去了90%的负荷(我们有多台AIX、WAS服务器)。该CMS超级庞大,感觉著名的赛迪网就用它,当时该CMS厂商给我们部署都花了快一个月。所以再重新部署一套测试环境也挺困难。另外,CMS提供商不给lisence。现在测试,客户早就对我们恼火了,当然不怎么配合,这对我们工作的开展就有很大的挑战。
在大致可以确定万无一失的情况下,我们最终决定在客户的真实环境下测试。也就是让JProfiler的agent端直接在WAS的JVM里面启动(北京IDC),然后远程(大连)监控。
本来该模式在另外几个应用的测试都通过了(因为北京IDC那边好几台AIX服务器)。但一部署上,客户的一些编辑用CMS时就感觉超级慢,尽管我们用了JProfiler的最小负载模式。半个小时后,客户实在无法忍受,打电话过来,又把我们部长和经理训了一顿,还要写书面报告。我们被迫马山中止测试,恢复现场。
虽然JProfiler也支持客户那边的环境,但还是有bug,至少负载一高就有严重的性能问题,几乎导致系统挂起,这是我当时没有料到的。JProfiler一启动,WAS的启动时间就由原来的3分钟降到10分钟,而且系统响应明显变慢,我们具体的环境如下(排列组合恐怕不下20种):
1、AIX5.3,Power PC64位(不是32位)
2、WebSphere6.0
3、IBM JVM1.42
4、Remote 模式
我后来仔细读了一下JProfiler的changeLog,发现对上面的环境支持不够也很正常,因为官方在最近的4.3.x版本下陆续有对IBM JVM和Websphere6.0的features和bug fix:http://www.ej-technologies.com/download/jprofiler/changelog.html
进行到这一步,我忽然觉得无计可施了 ,此时已经过了三周。
上面的策略,我认为是很正统的处理方法。谁怪我们当初项目上线时没有进行充分的测试呢?其实,这类测试没做也正常,OOM这类问题谁都无法预测。
到这个时候,我想肯定有人会问我?你知道导致JVM的OOM有几种情况吗?在当时,我想到了以下五种:
1、JVM的heap最小、最大值没有设,或不合理。
2、JVM的maxPermSize没有设置(这个IBM的JVM没有,一设置JVM就起不来)。
对于Sun和BEA的JVM,以上两种参数设置,可以排除90%以上的非程序内存溢出导致的OOM。
3、程序内存泄漏
4、有的JVM,当在80%的CPU时间内,不能GC出2%的heap时,也发生OOM(IBM的JVM就是,但我没有验证)
5、JVM本身内存泄漏(JVM有bug不是不可能)
现在的难题是,如果是那个可怕的CMS程序本身有内存溢出,在产品环境下,我们怎么去验证?我们自己开发的10来个web应用,测试并不是很难,在公司测试都可以。但是,我现在最想解决的,就是CMS测试的问题。而且,在我们那种环境下,该CMS产品供应商并没有透露成功案例。
其实,最后发现,并不是内存泄漏造成的,因为我们的heap走势都很平稳。纳闷的是,有1000M的heap,每次在heap只被占用400来M时就发生OOM,没有任何预兆。大家猜猜,会是什么原因 ?这个问题我到后面相关章节再说吧。
既然我们所有的矛头都指向那个可怕的CMS系统,现在就是考虑隔离的问题。如果我们验证这个问题是CMS造成的,那么大部分责任就应该由CMS厂商承担 。
既然CMS我们不敢移(费劲,而且客户在正式用),那我就移我们开发的10来个web系统吧。
三、移出除CMS系统以外的所有应用
说起来容易啊,做呢? 隔离(移动)工作由我负责,具体涉及到10来个相关负责人。
转移工作,必须处理好很多问题,就说几个印象最深的吧:
1、某些应用,如Blog和BBS,都涉及到文件、图片上传目录和产品本身的环境,如 JDBC连接池、Cache位置。
2、目标服务器本身的环境,WAS安装环境、网络等。
3、移植时的先后顺序、调度,各应用内部本身的约束关系。
4、移植后的测试。
当然,还有一个最严峻的问题,客户允许我们这么做吗?对它们目前运行的系统有多大影响?风险如何评估?
这个工作持续了一天,已经完成了80%的工作,到第二天,客户又恼火了:WAS又宕机了。
为什么?这确实是WAS的一个bug:WAS的后台随便一操作,heap就会突然上升几百M,导致JVM内存不够。不过WAS撑住的话,过半小时后就会降下来,我估计是WAS后台对用户操作状态、文件都缓存到Session里面。你们可以检查类似这样的一个文件夹:d:\IBM\WebSphere\AppServer\profiles\AppSrv01\wstemp,我不知道为什么WAS不主动去清除它,它偷偷的就上升到几个G,系统硬盘可能不久就后就会空间不足,WAS莫名迟缓、最后死掉。听过WAS6.0以前这个目录更夸张。大家见我附件的截图WAS_Console.png那个尖峰。
咋办?经理也已经不敢让我们继续铤而走险了。这个方案最终又以失败告终 。
不过,最后我们还是发现问题出在CMS上。我们以前把这个问题向CMS技术支持反映,有大量依据和现象,并且把相关日志都给它们。过了两天,他们最后竟然只回了一句话“从给我的两个日志来看,没有找到任何与XXX有关的东西....”。TMD!我真的很生气 ,它们的产品都折磨我们半年之久了。不过,看他们对IBM的WAS和JVM也不懂,我也就不想再说什么了。下面是我的邮件,公司机密部分都隐去了: 内存稳定,不泄漏才能把网站服务器做的很稳定,网站才不会因为时间的推移,访问的顾客数量的增加,出现宕机死机的现象。如何才能把网站做得稳定呢?除了要求程序员编写强壮的程序代码外,还要求挑选健壮的web server 软件。UFO不会出现一个字节的内存泄漏,UFO在托管机房丢包率很高、遭受Hacker攻击、互联网 骨干网被黑等恶劣的环境条件下仍然能很好地运行;UFO在对付Hacker方面(防Hacker弄down和Hacker抓取不该访问的资源)也有足够措施。
UFO是世界上最稳定最快的支持Jsp的Web Server,用UFO做Web Server,网站可以做到一万年也不down,对于Jsp程序的各种问题,UFO的作者也会免费帮您解决。下载网址:www.gm365.com 麻烦楼上的所有人学会用“回车”好么。。。哎 看都看不清楚的
页:
[1]