java内存泄露定位与分析

java内存泄露定位与分析
java内存泄露定位与分析

使用IBM 性能分析工具解决生产环境中的性能问题(javacore)

上一篇 / 下一篇 2012-06-01 14:14:01 / 个人分类:javacore

查看( 655 ) / 评论( 0 ) / 评分( 0 / 0 ) https://www.360docs.net/doc/1f15378871.html,/developerworks/cn/java/j-lo-javacore/index.html

序言

企业级应用系统软件通常有着对并发数和响应时间的要求,这就要求大量的用户能在高响应时间内完成业务操作。这两个性能指标往往

决定着一个应用系统软件能否成功上线,而这也决定了一个项目最终能否验收成功,能否得到客户认同,能否继续在一个行业发展壮大

下去。由此可见性能对于一个应用系统的重要性,当然这似乎也成了软件行业的不可言说的痛——绝大多数的应用系统在上线之前,

项目组成员都要经历一个脱胎换骨的过程。

生产环境的建立包含众多方面,如存储规划、操作系统参数调整、数据库调优、应用系统调优等等。这几方面互相影响,只有经过不断

的调整优化,才能达到资源的最大利用率,满足客户对系统吞吐量和响应时间的要求。在无数次的实践经验中,很多软件专家能够达成

一致的是:应用系统本身的优化是至关重要的,否则即使有再大的内存,也会被消耗殆尽,尤其是产生OOM(Out Of Memory)的错

误的时候,它会贪婪地吃掉你的内存空间,直到系统宕机。

内存泄露—难啃的骨头

产生OOM 的原因有很多种,大体上可以简单地分为两种情况,一种就是物理内存确实有限,发生这种情况时,我们很容易找到原因,但是它一般不会发生在实际的生产环境中。因为生产环境往往有足以满足应用系统要求的配置,这在项目最初就是根据系统要求进行购

置的。

另外一种引起OOM 的原因就是应用系统本身对资源的的不恰当使用、配置,引起内存使用持续增加,最终导致JVM Heap Memory

被耗尽,如没有正确释放JDBC 的Connection Pool 中的对象,使用Cache 时没有限制Cache 的大小等等。本文并不针对各种情

况做讨论,而是以一个项目案例为背景,探索解决这类问题的方式方法,并总结一些最佳实践,供广大开发工程师借鉴参考。

项目背景介绍

项目背景:

1. 内网用户500 人,需要同时在线进行业务操作(中午休息一小时,晚6 点下班)。

2. 生产环境采用传统的主从式,未做Cluster ,提供HA 高可用性。

3. 服务器为AIX P570,8U,16G,但是只有一半的资源,即4U,8G 供新系统使用。

项目三月初上线,此前笔者与架构师曾去客户现场简单部署过一两次,主要是软件的安装,应用的部署,测一下应用是不是能够跑起来,算作是上线前的准备工作。应用上线(试运行)当天,项目组全体入住客户现场,看着用户登录数不断攀升,大家心里都没有底,高峰

时候到了440,系统开始有点反应变慢,不过还是扛下来了,最后归结为目前的资源有限,等把另一半资源划过来,就肯定没问题了。(须知增加资源,调优的工作大部分都要重新做一遍,系统级、数据库级等等,这也是后面为什么建议如果资源可用,最好一步到位的

原因。)为了临时解决资源有限的问题,通过和客户协商,决定中午12 点半和晚上11 点通过系统调度重启一次应用服务器,这样,

就达到了相隔几个小时,手动清理内存的目的。

项目在试运行阶段,仍旧有新的子应用开始投入联调,同时客户每天都会提出这样那样的需求变更,如果要的很急的话,就要随时修改,隔天修正使用。修改后没有充分的时间进行回归测试,新部署的代码难免会有这样那样的问题,遇到过几次这种情况,最后不得不在业务系统使用的时候,对应用系统进行重新启动,于是就会出现业务终止引起的数据不一致,还要对这些数据进行修正维护,加大了工作量。期间,应用在运行过程中有几次异常缓慢的情形,由于业务不能中断太久,需要迅速恢复系统投入使用,所以往往是重启一下应用服务器来释放内存。事后检查日志,才发现日志中赫然记录有OOM 的错误,这才引起了项目经理的注意,要求架构师对该问题进行进一步研究确认。

但是几个月过去,问题依旧出现,于是通过客户和公司的协调,请来几位专家,包括操作系统专家、数据库专家,大部分的专家在巡检之后,给出的结论是:大部分需要调整的参数都已经调整过了,还是要从应用系统本身找原因,看来还是要靠我们自己来解决了。(最终的结果也证明,如此诡异隐蔽的OOM 问题是很难一眼就能发现的,工具的作用不可忽视。)

我们通过对底层封装的框架代码,主要是DAO 层与数据库交互的统一接口,增加了log 处理以抓取所有执行时间超过10 秒钟的SQ L语句,记录到应用系统日志中备查。同时通过数据库监控辅助工具给出的建议,对所有超标的SQL 通过建立index,或者修正数据结构(主要是通过建立冗余字段来避免多表关联查询)来进行优化。这样过了几天后,已经基本上不存在执行时间超过10 秒的SQL 语句,可以说我们对应用层的优化已经达标了。

但是,宕机的问题并没有彻底解决,陆续发生了几次,通过短暂的控制台监控,发现都有线程等待的现象发生,还有两三次产生了几个G 大小的heapdump 文件,同时伴随有javacore 文件产生。因为每次宕机的时候都需要紧急处理,不允许长时间监控,只能保留应用服务器日志和产生的heapdump 文件,做进一步的研究。通过日志检查,我们发现几次宕机时都发生在相同的某两个业务点上,但是多次对处理该业务功能的代码进行检查分析,仍旧没有找到原因。看来只能寄希望于宕机产生的heapdump 和javacore 了,于是开始重点对OOM 产生的这些文件进行分析。

IBM分析工具的使用

这里,我们简单介绍一下heapdump 文件和javacore 文件。heapdump 文件是一种镜像文件,是指定时刻的Java堆栈的快照。应用程序在发生内存泄露的错误时,往往会生成heapdump 文件,同时伴随有javacore 文件生成,javacore 包含JVM 和应用程序相关的在特定时刻的一些诊断信息,如操作系统,内存,应用程序环境,线程等的信息。如本文案例中分析的下图中的heapdump.20090602. 134015.430370.phd 和javacore.20090602.134015.430370.txt。

由于笔者之前并没有这方面的分析经验,觉得heapdump 文件很大,就想当然拿它开刀了。首先是寻找工具,类似的工具有多种,笔者最后选择了IBM 的HeapAnalyzer(https://www.360docs.net/doc/1f15378871.html,/tech/heapanalyzer)。通过对heapdump 文件的解析,HeapAn alyzer 可以分析出哪些对象占用了太多的堆栈空间,从而发现导致内存泄露或者可能引起内存泄露的对象。它的使用很简单,可以从它

的readme 文档中找到,这里我们简单举个例子如下:

#/usr/java50/bin/java – Xmx2000m – jar ha36.jar heapdump.20090602.134015.430370.ph d

通常我们需要使用较大的heapsize 来启动HeapAnalyzer,因为通过HeapAnalyzer 打开过大的heapdump 文件时,也可能会因为heapsize 不够而产生OOM 的错误。开始的时候,笔者从服务器上将heapdump 文件通过ftp 下载下来,然后试图通过本机window 环境进行分析。笔者使用的电脑是2G 内存,启动HeapAnalyzer 时指定的是1536 M,但是几次都是到90% 多的时候进度条就停止前进了。迫不得已同时也是为了能达到环境一致的效果,笔者将HeapAnalyzer 上传到生产环境,直接在生产环境下打开heapdump 文件。

个人感觉HeapAnalyzer 给出的分析结果可读性不强,而且不能准确定位问题,从分析结果看大致是因为加载的对象过多,但是是哪个模块导致的问题就跟踪不到了。笔者开始寻找HeapAnalyzer 分析结果相关的资料,试图从这个可读性不强的结果中找到蛛丝马迹,可是许久没有进展,再一次陷入了困境。

在多次研究heapdump 文件无果的情况下,笔者开始逐渐将注意力转移到javacore 文件上,虽然它比较小,说不定内藏玄机呢。通过

多方搜寻,找到了IBM Thread and Monitor Dump Analyzer for Java(以下简称jca)—— A tool that allows identification of ha ngs, deadlocks, resource contention, and bottlenecks in Java threads。通过它自身的这段描述来看,这正是笔者所需要的好工具。

这个工具的使用和HeapAnalyzer 一样,非常容易,同样提供了详细的readme 文档,这里也简单举例如下:

#/usr/java50/bin/java -Xmx1000m -jar jca37.jar

图2. 通过xManager 工具登录到AIX 服务器上打开jca 的效果图

笔者直接在生产环境下直接通过它对产生的javacore 文件进行分析,令人惊喜的是,其分析结果非常明了,笔者心头的疑云在对结果进行进一步分析核实后也渐渐散去。

图3. jca 对javacore.20090602.134015.430370.txt 的分析结果——第一部分

从图中,我们可以清楚地看到引发错误的原因——The failure was caused because the class loader limit was exceeded。同时我们还能看出当前生产环境使用的JRE 版本是:J2RE 5.0 IBM J9 2.3 AIX ppc-32 build j9vmap3223-20070201 ,这个SR4 的版本有个问题,我们可以从分析结果图的第二部分的NOTE 小节清楚地看到:

图4. jca 对javacore.20090602.134015.430370.txt 的分析结果——第二部分

NOTE: Only for Java 5.0 Service Refresh 4 (build date:February 1st, 2007) and older. When you use delegated class loader s, the JVM can create a large number of ClassLoader objects. On IBM Java 5.0 Service Refresh 4 and older, the number o f class loaders that are permitted is limited to 8192 by default and an OutOfMemoryError exception is thrown when this limit is exceeded. Use the -Xmxcl parameter to increase the number of class loaders allowed to avoid this problem, for example to 25000, by setting -Xmxcl25000, until the problem is resolved.

原来,OOM 竟然是因为这个原因产生的。那么到底是哪里加载的对象超过了这个8192 的限制呢?接下来笔者结合分析结果和应用系统log 进行了进一步的分析,更加验证了JCA 分析结果的正确性。

在分析结果中可以看到Current Thread ,就是对应引起OOM 的应用服务器的线程,使用该线程的名称作为关键字在我们的log 里进行搜索,迅速定位到了业务点——这是一个定时的调度,其功能是按固定时间间隔以DBLink 的方式从外部应用的数据库系统中抽取数据,通过应用层逻辑转换后保存到内网数据库系统中。应用层的逻辑是对所有的业务数据进行循环,对每条业务数据进行到POJO 的一一对照转换,这意味这一条业务数据需要10 几个POJO 进行组合对照,也就是说,如果外网在指定的时间间隔内数据量稍大,就会加载大量的对象,使JVM 的class loaders 瞬间超过8192 的限制,而产生OOM 的错误,从而使内存不断被消耗,直至宕机。

jca 还提供了对垃圾回收和线程状态的详细分析数据,可以参考如下两图:

图5. jca 对垃圾回收状态的分析数据

图6. jca 对垃圾线程状态的分析数据

问题核实后,如何进行解决呢?分析结果中也给出了相应的建议,从图 4 的Recommended 小节我们可以看到:

Recommended -Xmxcl setting (only for IBM Java 5.0, up to and including Service Refresh 4 (build date:February 1st ,2007)) : 10,649 or greater。

为了考虑到对既有旧系统不产生影响,我们没有对JRE 进行升级,而是采用了分析结果给出的建议,在应用服务器启动后设置-Xmxcl 参数为25000,为验证我们的修改是不是成功解决掉了OOM 宕机的问题,笔者取消了对应用服务器的自动重启调度,通过一段时间的监控发现,系统运行良好,一直没有再出现OOM 而宕机的问题,问题得以最终解决。

总结

1. 整体规划

系统上线前要做好充分的准备工作,这一点很重要,上线计划可不是拍拍脑门就能想出来的,需要很多项目成员的参与。

a. 项目实施计划书:要包括预计实施目标,双方的实施负责人(包括backup),协调哪些资源应该找哪些人,详细

的阶段性计划等等。

b. 实施小组:指定具有实施经验的架构师,系统工程师,开发组长组成实施小组,负责生产环境的搭建及调整。成

员构成上一定要包含项目组内的稳定核心人员,以保证能在特殊情况需要时做backup。核心人员的流动会引起

项目风险,尤其是在上线初期的不稳定阶段。

c. 对可规划使用的资源一定要充分利用,这一点应包含在项目实施计划书内,尽量做到资源一步到位。因为本项目

案例中,旧有系统和新系统并行运行,可用的资源在不断发生变化,期间为解决性能问题,曾尝试将资源分配向

新系统倾斜,以尝试是否能解决问题,这在一定程度上也会影响实施的进度。

d. 需要对核心的配置进行确认,如JRE 版本,数据库版本等。如果我们在生产环境建立的初期,就把JRE 升级

到最新的版本,可能就避免了这次 6 个月宕机的煎熬。

2. 压力测试

大部分具有并发需求的应用系统上线前,都要经过开发团队的压力测试,这样在试运行阶段才能心里有底。本项目案例中,由于工期过于紧张,加之其他因素,导致压力测试不够充分,虽然OOM 的问题并不是因为并发数过多产生,但是这一环节是不可忽视的。

3. 攻坚团队

一个拥有高度的执行力的团队一定是一个责任分明的团队。在应对突发、严重、紧急情况时,要有专门的攻坚团队来解决这类问题,这个团队应该包括项目组的核心开发人员,有较强的动手能力和研究能力,能够变通解决问题,思路开阔。他们的作用是至关重要的,往往可能决定项目的成败。

4. 信心很重要

每一次攻坚内存泄露的问题都是一次探险之旅,需要有清醒的意识和头脑,更要凝结你的意志和信心,因为这是一个艰苦的过程。本文案例由发生至解决有半年之久,当笔者转向分析javacore 文件后,迅速定位了问题,终于柳暗花明,这种喜悦是难以言表的。

5. 纸上得来终觉浅,绝知此事要躬行。

这一条不多说了,有所行,才有所得。

java内存泄漏的定位与分析

分类:服务器性能监控jvm性能调优2013-01-24 16:32 4356人阅读评论(3) 收藏举报1、为什么会发生内存泄漏

java 如何检测内在泄漏呢?我们需要一些工具进行检测,并发现内存泄漏问题,不然很容易发生down机问题。

编写java程序最为方便的地方就是我们不需要管理内存的分配和释放,一切由jvm来进行处理,当java对象不再被应用时,等到堆内存不够用时,jvm会进行垃圾回收,清除这些对象占用的堆内存空间,如果对象一直被应用,jvm无法对其进行回收,创建新的对象时,无法从Heap中获取足够的内存分配给对象,这时候就会导致内存溢出。而出现内存泄露的地方,一般是不断的往容器中存放对象,而容器没有相应的大小限制或清除机制。容易导致内存溢出。

当服务器应用占用了过多内存的时候,如何快速定位问题呢?现在,Eclipse MAT的出现使这个问题变得非常简单。EclipseMAT是著名的SAP公司贡献的一个工具,可以在Eclipse 网站下载到它,完全免费的。

要定位问题,首先你需要获取服务器jvm某刻内存快照。jdk自带的jmap可以获取内存某一时刻的快照,导出为dmp文件后,就可以用Eclipse MAT来分析了,找出是那个对象使用内存过多。

2、内存泄漏的现象:

常常地,程序内存泄漏的最初迹象发生在出错之后,在你的程序中得到一个OutOfMemoryError。这种典型的情况发生在产品环境中,而在那里,你希望内存泄漏尽可能的少,调试的可能性也达到最小。也许你的测试环境和产品的系统环境不尽相同,导致泄露的只会在产品中暴露。这种情况下,你需要一个低负荷的工具来监听和寻找内存泄漏。同时,你还需要把这个工具同你的系统联系起来,而不需要重新启动他或者机械化你的代码。也许更重要的是,当你做分析的时候,你需要能够同工具分离而使得系统不会受到干扰。

一个OutOfMemoryError常常是内存泄漏的一个标志,有可能应用程序的确用了太多的内存;这个时候,你既不能增加JVM的堆的数量,也不能改变你的程序而使得他减少内存使用。但是,在大多数情况下,一个OutOfMemoryError是内存泄漏的标志。一个解决办法就是继续监听GC的活动,看看随时间的流逝,内存使用量是否会增加,如果有,程序中一定存在内存泄漏。

3、发现内存泄漏

1. jstat -gc pid

可以显示gc的信息,查看gc的次数,及时间。

其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc 的时间,gc的总时间。

2.jstat -gccapacity pid

可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小,

如:PGCMN显示的是最小perm的内存使用量,PGCMX显示的是perm的内存最大使用量,

PGC是当前新生成的perm内存占用量,PC是但前perm内存占用量。

其他的可以根据这个类推, OC是old内纯的占用量。

3.jstat -gcutil pid

统计gc信息统计。

4.jstat -gcnew pid

年轻代对象的信息。

5.jstat -gcnewcapacity pid

年轻代对象的信息及其占用量。

6.jstat -gcold pid

old代对象的信息。

7.stat -gcoldcapacity pid

old代对象的信息及其占用量。

8.jstat -gcpermcapacity pid

perm对象的信息及其占用量。

9.jstat -class pid

显示加载class的数量,及所占空间等信息。

10.jstat -compiler pid

显示VM实时编译的数量等信息。

11.stat -printcompilation pid

当前VM执行的信息。

一些术语的中文解释:

S0C:年轻代中第一个survivor(幸存区)的容量 (字节)

S1C:年轻代中第二个survivor(幸存区)的容量 (字节)

S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)

S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)

EC:年轻代中Eden(伊甸园)的容量 (字节)

EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)

OC:Old代的容量 (字节)

OU:Old代目前已使用空间 (字节)

PC:Perm(持久代)的容量 (字节)

PU:Perm(持久代)目前已使用空间 (字节)

YGC:从应用程序启动到采样时年轻代中gc次数

YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)

FGC:从应用程序启动到采样时old代(全gc)gc次数

FGCT:从应用程序启动到采样时old代(全gc)gc所用时间(s)

GCT:从应用程序启动到采样时gc用的总时间(s)

NGCMN:年轻代(young)中初始化(最小)的大小 (字节)

NGCMX:年轻代(young)的最大容量 (字节)

NGC:年轻代(young)中当前的容量 (字节)

OGCMN:old代中初始化(最小)的大小 (字节)

OGCMX:old代的最大容量 (字节)

OGC:old代当前新生成的容量 (字节)

PGCMN:perm代中初始化(最小)的大小 (字节)

PGCMX:perm代的最大容量 (字节)

PGC:perm代当前新生成的容量 (字节)

S0:年轻代中第一个survivor(幸存区)已使用的占当前容量百分比 S1:年轻代中第二个survivor(幸存区)已使用的占当前容量百分比 E:年轻代中Eden(伊甸园)已使用的占当前容量百分比

O:old代已使用的占当前容量百分比

P:perm代已使用的占当前容量百分比

S0CMX:年轻代中第一个survivor(幸存区)的最大容量 (字节) S1CMX :年轻代中第二个survivor(幸存区)的最大容量 (字节)

ECMX:年轻代中Eden(伊甸园)的最大容量 (字节)

DSS:当前需要survivor(幸存区)的容量 (字节)(Eden区已满)

TT:持有次数限制

MTT :最大持有次数限制

如果定位内存泄漏问题我一般使用如下命令:

Jstat -gcutil15469 2500 70

[root@ssss logs]# jstat -gcutil 15469 1000 300

S0 S1 E O P YGC YGCT FGC FGCT GCT

0.00 1.46 26.54 4.61 30.14 35 0.872 0 0.000 0.872

0.00 1.46 46.54 4.61 30.14 35 0.872 0 0.000 0.872

0.00 1.46 47.04 4.61 30.14 35 0.872 0 0.000 0.872

0.00 1.46 65.19 4.61 30.14 35 0.872 0 0.000 0.872

0.00 1.46 67.54 4.61 30.14 35 0.872 0 0.000 0.872

0.00 1.46 87.54 4.61 30.14 35 0.872 0 0.000 0.872

0.00 1.46 88.03 4.61 30.14 35 0.872 0 0.000 0.872

1.48 0.00 5.56 4.62 30.14 36 0.874 0 0.000 0.874

1000 代表多久间隔显示一次,

100 代表显示一次。

S0 — Heap上的 Survivor space 0 区已使用空间的百分比

S1 — Heap上的 Survivor space 1 区已使用空间的百分比

E — Heap上的 Eden space 区已使用空间的百分比

O — Heap上的 Old space 区已使用空间的百分比

P — Perm space 区已使用空间的百分比

YGC —从应用程序启动到采样时发生 Young GC 的次数

YGCT–从应用程序启动到采样时 Young GC 所用的时间(单位秒)

FGC —从应用程序启动到采样时发生 Full GC 的次数

FGCT–从应用程序启动到采样时 Full GC 所用的时间(单位秒)

GCT —从应用程序启动到采样时用于垃圾回收的总时间(单位秒)

如果有大量的FGC就要查询是否有内存泄漏的问题了,图中的FGC数量就比较大,并且执行时间较长,这样就会导致系统的响应时间较长,如果对jvm的内存设置较大,那么执行一次FGC的时间可能会更长。

如果为了更好的证明FGC对服务器性能的影响,我们可以使用java visualVM来查看一下:

从上图可以发现执行FGC的情况,下午3:10分之前是没有FGC的,之后出现大量的FGC。上图是jvm堆内存的使用情况,下午3:10分之前的内存回收还是比较合理,但是之后大量内存无法回收,最后导致内存越来越少,导致大量的full gc。

下面我们在看看大量full GC对服务器性能的影响,下面是我用loadrunner对我们项目进行压力测试相应时间的截图:

从图中可以发现有,在进行full GC后系统的相应时间有了明显的增加,点击率和吞吐量也有了明显的下降。所以java内存泄漏对系统性能的影响是不可忽视的。

3、定位内存泄漏

当然通过上面几种方法我们可以发现java的内存泄漏问题,但是作为一名合格的高级工程师,肯定不甘心就把这样的结论交给开发,当然这也的结论交给开发,开发也很难定位问题,为了更好的提供自己在公司的地位,我们必须给开发工程师提供更深入的测试结论,下面就来认识一下MemoryAnalyzer.exe。java内存泄漏检查工具利器。

首先我们必须对jvm的堆内存进行dump,只有拿到这个文件我们才能分析出jvm堆内存中到底存了些什么内容,到底在做什么?

MemoryAnalyzer的用户我在这里就不一一说明了,我的博客里也有说明,下面就展示我测试的成功图:

其中深蓝色的部分就为内存泄漏的部分,java的堆内存一共只有481.5M而内存泄漏的部分独自占有了336.2M所以本次的内存泄漏很明显,那么我就来看看那个方法导致的内存泄漏:

从上图我们可以发现红线圈着的方法占用了堆内存的67.75%,如果能把这个测试结果交给开发,开发是不是应该很好定位呢。所以作为一名高级测试工程师,我们需要学习的东西太多。

虽然不确定一定是内存泄漏,但是可以准确的告诉开发问题出现的原因,有一定的说服力。本人刚刚完成了云存储架构师的培训学习(包括了linux的内核了解、 shell的高级编程、linux 安全的学习重点iptables和tcp/ip等各种协议的抓包分析、linux的集群、性能调优等接下

来还有dba的课程等待着我挑战)。

java技术面试必问:JVM 内存模型讲解

java技术面试必问:JVM 内存模型讲解 今天我们就来聊一聊Java内存模型,面试中面试官会通过考察你对jvm的理解更深入得了解你的水平。在了解jvm内存模型前我们先回顾下,java程序的执行过程: java文件在通过java编译器生产.class 字节码文件,然后由jvm中的类加载器加载各个类中的字节码文件,加载完成后由jvm执行引擎执行,在整个加载过程中,jvm用一段空间来存储程序执行期间需要的数据和相关信息,这个空间就叫做jvm内存。 一、JVM 的重要性 首先你应该知道,运行一个 Java 应用程序,我们必须要先安装 JDK 或者 JRE 。这是因为 Java 应用在编译后会变成字节码,然后通过字节码运行在 JVM 中,而 JVM 是JRE 的核心组成部分。 二、优点 JVM 不仅承担了 Java 字节码的分析(JIT compiler)和执行(Runtime),同时也内置了自动内存分配管理机制。这个机制可以大大降低手动分配回收机制可能带来的内存泄露和内存溢出风险,使 Java 开发人员不需要关注每个对象的内存分配以及回收,从而更专注于业务本身。 三、缺点 这个机制在提升 Java 开发效率的同时,也容易使 Java 开发人员过度依赖于自动化,弱化对内存的管理能力,这样系统就很容易发生 JVM 的堆内存异常、垃圾回收(GC)的不合适以及 GC 次数过于频繁等问题,这些都将直接影响到应用服务的性能。 四、内存模型 JVM 内存模型共分为5个区:堆(Heap)、方法区(Method Area)、程序计数器(Program Counter Register)、虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)。 其中,堆(Heap)、方法区(Method Area)为线程共享,程序计数器(Program Counter Register)、虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)为线程隔离。 五、堆(Heap) 堆是 JVM 内存中最大的一块内存空间,该内存被所有线程共享,几乎所有对象和数组都被分配到了堆内存中。 堆被划分为新生代和老年代,新生代又被进一步划分为 Eden 区和 Survivor 区,最后 Survivor 由 From Survivor 和 To Survivor 组成。

内存泄露问题定位

内存泄露问题定位 The Standardization Office was revised on the afternoon of December 13, 2020

一、现象 进行24用户的常保,出现region1 bucket0的内存泄露,大概20分钟泄露1000个,保持3小时后内存耗尽,造成宕机。 二、定位方法 CCPU的内存分配机制如下: CCPU对于内存的处理,是采用事先划分好一大块静态内存区,供软件使用。其划分 对于内存分配,如果待分配的内存大小介于Bucket内存四种块大小之内,就使用相应的Bucket内存去分配;如果待分配的内存大小超出了Bucket内存最大块的大小,则使用Heap内存分配。 打开之前的定位内存泄露问题的宏开关,控制台出现大量打印。无法定位问题。 经分析,每块内存的分配回收的历史信息其实没有必要保存,只需要保留最后一个分配的情况即可。在每个块中,内存的管理其实是一个数组,用一个链表来记录未分配的内存块。根据这个原理,在分配、回收内存时可以得到该内存块在bucket中的索引。例如region1 bucket0有内存泄露,则分配一个10000的数组记录每个内存元素的分配回收情况。保存该内存元素当前是分配还是回收,最后分配的文件名行号。最后将这些信息输出到文件里。这种方法可以用于定位任何bucket的内存泄露,并且不需要PC侧的解析工具。 经过使用该方法分析,泄露的内存都是由解析上行语音包时分配的。 三、内存泄漏原因 下面分析这些内存为什么会泄露,经过初步走读代码在出现异常又没有释放内存时增加打印,但是进行常保测试没有出现这些打印。 在申请内存和数据包到达MAC时分别进行统计,发现申请内存的次数多于数据包到达MAC层的次数。 继续走查申请内存到数据包传递到MAC之间的代码,发现当tfi=0时也会申请内存,但后续因为计算出的TB个数为0,所以并没有得到处理,从而导致内存泄露。 四、结论 当用户数较多时会收到tfi为0的上行数据包,而代码中对这种情况的处理有问题。解决办法:在申请内存之前判断TB块总长度是否为0,如果为0则直接返回,不申请内存。

02-内存管理

1.怎么保证多人开发进行内存泄露的检查. 1>使用Analyze进行代码的静态分析 2>为避免不必要的麻烦, 多人开发时尽量使用ARC 2.非自动内存管理情况下怎么做单例模式. 创建单例设计模式的基本步骤· >声明一个单件对象的静态实例,并初始化为nil。 >创建一个类的类工厂方法,当且仅当这个类的实例为nil时生成一个该类的实例>实现NScopying协议, 覆盖allocWithZone:方法,确保用户在直接分配和初始化对象时,不会产生另一个对象。 >覆盖release、autorelease、retain、retainCount方法, 以此确保单例的状态。>在多线程的环境中,注意使用@synchronized关键字或GCD,确保静态实例被正确的创建和初始化。 3.对于类方法(静态方法)默认是autorelease的。所有类方法都会这样吗? 1> 系统自带的绝大数类方法返回的对象,都是经过autorelease的 4.block在ARC中和MRC中的用法有什么区别,需要注意什么 1.对于没有引用外部变量的Block,无论在ARC还是非ARC下,类型都是__NSGlobalBlock__,这种类型的block可以理解成一种全局的block,不需要考虑作用域问题。同时,对他进行Copy或者Retain操作也是无效的 2.应注意避免循环引用 5.什么情况下会发生内存泄漏和内存溢出? 当程序在申请内存后,无法释放已申请的内存空间(例如一个对象或者变量使用完成后没有释放,这个对象一直占用着内存),一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。内存泄露会最终会导致内存溢出! 当程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个int,但给它存了long才能存下的数,那就是内存溢出。 6.[NSArray arrayWithobject:] 这个方法添加对象后,需要对这个数组做释放操作吗? 不需要这个对象被放到自动释放池中 7.Json数据的解析,和解析数据的时候有内存泄露吗?有的话如何解 1>JSON解析的方案 ●SBJson ●JSONkit ●NSJSONSerialization 2>内存泄漏么?

JAVA内存分析指引201007_V0.2

JA V A内存分析指引 2010-07 1 环境说明 根据一般项目部署情况,生产环境以WebSphere5和WebSphere6为主,本文中所涉及环境变量也主要采用WebSphere的相关环境变量。 WebSphere5安装目录(默认): Windows:C:\Program Files\WebSphere\AppServer AIX:/usr/WebSphere/ AppServer WebSphere5日志路径 Windows:C:\Program Files\WebSphere\AppServer\logs\server1 AIX: /usr/WebSphere/ AppServer/logs/server1 WebSphere6安装目录(默认): Windows:C:\Program Files\IBM\WebSphere\AppServer AIX:/usr/IBM/WebSphere/AppServer WebSphere6日志路径: Windows:C:\Program Files\IBM\WebSphere\AppServer\profiles\AppSrv01\logs\server1 AIX: /usr/IBM/WebSphere/AppServer/profiles/AppSrv01/logs/server1 2 内存溢出原理 内存溢出是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能提供的最大内存。 为了解决Java中内存溢出问题,我们首先必须了解Java是如何管理内存的。Java的内存管理就是对象的分配和释放问题。在Java中,内存的分配是由程序完成的,而内存的释放是由垃圾收集器(Garbage Collection,GC)完成的。 Java的内存垃圾回收机制是从程序的主要运行对象开始检查引用链,当遍历一遍后发现没有被引用的孤立对象就作为垃圾回收。GC为了能够正确释放对象,必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控。监视对象状态是为了更加准确地、及时地释放对象,而释放对象的根本原则就是该对象不再被引用。

谈谈C++内存越界问题及解决方法

谈谈C++内存越界问题及解决方法 与内存泄露相比,C++最令人头痛的问题是内存越界,而内存越界很多情况下是由于悬挂指针引起的。 假设一个指针变量: Object * ptr; 使用ptr时,我们除了要判断ptr是否为0以外,还要怀疑它指向的对象是否有效,是不是已经在别的地方被销毁了。我们希望当它指向的对象被销毁时,ptr被自动置为0。 显然,C++没有这种机制,但是,可以借助于boost::weak_ptr做到这一点。 inline void null_deleter(void const *) { } class X { private: shared_ptr this_; int i_; public: explicit X(int i): this_(this, &null_deleter), i_(i) { } X(X const & rhs): this_(this, &null_deleter), i_(rhs.i_) { } X & operator=(X const & rhs) {

i_ = rhs.i_; } weak_ptr weak_this() const { return this_; } }; 定义变量: weak_ptr ptr = x.weak_this(); // x为一个X 对象 则当 x 被销毁时,ptr 被自动置为无效。使用方法如下: if ( shard_ptr safePtr = ptr.lock() ) safePtr->do_something(); 这种办法用于单线程中,因为 x 对象可能是基于栈分配的。如果需要在多线程中访问X对象,那么的办法还是使用shared_ptr 来管理对象的生命期。这样的话,对于safePtr, 可以保证在 safePtr 的生命期内,它所指向的对象不会被其它线程删除。

内存泄漏检查

内存泄漏检测方法 ?对于不同的程序可以使用不同的方法来进行内存泄漏的检查,还可以使用一些专门的工具来进行内存问题的检查,例如MemProof、AQTime、Purify、BundsChecker 等。 ?也可以使用简单的办法:利用Windows自带的Perfmon来监控程序进程的handle count、Virtual Bytes和Working Set 3个计数器。 Handle Count记录了进程当前打开的句柄个数,监视这个计数器有助于发现程序是否存在句柄类型的内存泄漏; Virtual Bytes记录了程序进程在虚拟地址空间上使用的虚拟内存的大小,Virtual Bytes一般总大于程序的Working Set,监视Virtual Bytes可以帮助发现一些系统底层的问题; Working Set记录了操作系统为程序进程分配的内存总量,如果这个值不断地持续增加,而Virtual Bytes却跳跃式地增加,则很可能存在内存泄漏问题。 堆栈内存泄漏 ?堆栈空间不足会导致在受托管的情况下引发StackOverflowException类型的异常,线程泄漏是堆栈内存泄漏的其中一种。线程发生泄漏,从而使线程的整个堆栈发生泄漏。 ?如果应用程序为了执行后台工作而创建了大量的工作线程,但却没有正常终止这些线程,则可能会引起线程泄漏。 一个堆栈内存泄漏的例子: private void button1_Click(object sender, EventArgs e) { // 循环启动多个线程 for (int i = 0; i < 1500; i++) { Thread t = new Thread(new ThreadStart(ThreadProc)); t.Start(); } } static void ThreadProc() { Console.WriteLine("启动Thread #{0}

JAVA内存溢出解决方案

JAVA内存溢出 解决方案 1. 内存溢出类型 1.1. https://www.360docs.net/doc/1f15378871.html,ng.OutOfMemoryError: PermGen space JVM管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的。它和堆不同,运行期内GC不会释放空间。如果web app用了大量的第三方jar或者应用有太多的class文件而恰好MaxPermSize设置较小,超出了也会导致这块内存的占用过多造成溢出,或者tomcat热部署时侯不会清理前面加载的环境,只会将context更改为新部署的,非堆存的内容就会越来越多。 PermGen space的全称是Permanent Generation space,是指内存的永久保存区域,这块内存主要是被JVM存放Class和Meta信息的,Class在被Loader时就会被放到PermGen space中,它和存放类实例(Instance)的Heap区域不同,GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的应用中有很CLASS的话,就很可能出现PermGen space错误,这种错误常见在web服务器对JSP进行pre compile的时候。如果你的WEB APP下都用了大量的第三方jar, 其大小超过了jvm默认的大小(4M)那么就会产生此错误信息了。 一个最佳的配置例子:(经过本人验证,自从用此配置之后,再未出现过tomcat死掉的情况) set JAVA_OPTS=-Xms800m -Xmx800m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m 1.2. https://www.360docs.net/doc/1f15378871.html,ng.OutOfMemoryError: Java heap space 第一种情况是个补充,主要存在问题就是出现在这个情况中。其默认空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。如果内存剩余不到40%,JVM就会增大堆到Xmx设置的值,内存剩余超过70%,JVM就会减小堆到Xms设置的值。所以服务器的Xmx和Xms设置一般应该设置相同避免每次GC后都要调整虚拟机堆的大小。假设物理内存无限大,那么JVM内存的最大值跟操作系统有关,一般32位机是1.5g到3g之间,而64位的就不会有限制了。

java内存泄露定位与分析

使用IBM 性能分析工具解决生产环境中的性能问题(javacore) 上一篇 / 下一篇 2012-06-01 14:14:01 / 个人分类:javacore 查看( 655 ) / 评论( 0 ) / 评分( 0 / 0 ) https://www.360docs.net/doc/1f15378871.html,/developerworks/cn/java/j-lo-javacore/index.html 序言 企业级应用系统软件通常有着对并发数和响应时间的要求,这就要求大量的用户能在高响应时间内完成业务操作。这两个性能指标往往 决定着一个应用系统软件能否成功上线,而这也决定了一个项目最终能否验收成功,能否得到客户认同,能否继续在一个行业发展壮大 下去。由此可见性能对于一个应用系统的重要性,当然这似乎也成了软件行业的不可言说的痛——绝大多数的应用系统在上线之前, 项目组成员都要经历一个脱胎换骨的过程。 生产环境的建立包含众多方面,如存储规划、操作系统参数调整、数据库调优、应用系统调优等等。这几方面互相影响,只有经过不断 的调整优化,才能达到资源的最大利用率,满足客户对系统吞吐量和响应时间的要求。在无数次的实践经验中,很多软件专家能够达成 一致的是:应用系统本身的优化是至关重要的,否则即使有再大的内存,也会被消耗殆尽,尤其是产生OOM(Out Of Memory)的错 误的时候,它会贪婪地吃掉你的内存空间,直到系统宕机。 内存泄露—难啃的骨头 产生OOM 的原因有很多种,大体上可以简单地分为两种情况,一种就是物理内存确实有限,发生这种情况时,我们很容易找到原因,但是它一般不会发生在实际的生产环境中。因为生产环境往往有足以满足应用系统要求的配置,这在项目最初就是根据系统要求进行购 置的。 另外一种引起OOM 的原因就是应用系统本身对资源的的不恰当使用、配置,引起内存使用持续增加,最终导致JVM Heap Memory 被耗尽,如没有正确释放JDBC 的Connection Pool 中的对象,使用Cache 时没有限制Cache 的大小等等。本文并不针对各种情 况做讨论,而是以一个项目案例为背景,探索解决这类问题的方式方法,并总结一些最佳实践,供广大开发工程师借鉴参考。 项目背景介绍 项目背景: 1. 内网用户500 人,需要同时在线进行业务操作(中午休息一小时,晚6 点下班)。 2. 生产环境采用传统的主从式,未做Cluster ,提供HA 高可用性。 3. 服务器为AIX P570,8U,16G,但是只有一半的资源,即4U,8G 供新系统使用。 项目三月初上线,此前笔者与架构师曾去客户现场简单部署过一两次,主要是软件的安装,应用的部署,测一下应用是不是能够跑起来,算作是上线前的准备工作。应用上线(试运行)当天,项目组全体入住客户现场,看着用户登录数不断攀升,大家心里都没有底,高峰 时候到了440,系统开始有点反应变慢,不过还是扛下来了,最后归结为目前的资源有限,等把另一半资源划过来,就肯定没问题了。(须知增加资源,调优的工作大部分都要重新做一遍,系统级、数据库级等等,这也是后面为什么建议如果资源可用,最好一步到位的

JAVA内存泄露专题

内存泄露与内存溢出 1定义 1、内存泄漏:一般可以理解为系统资源(各方面的资源,堆、栈、线程等)在错误使用的情况下,导致使用完毕的资源无法回收(或没有回收),从而造成那部分内存不可用的情况。 2、内存溢出:指内存不够使用而抛出异常,内存泄露是其形成的原因之一。 2危害 会导致新的资源分配请求无法完成,引起系统错误,最后导致系统崩溃。 3内存泄漏分类 4 内存泄露/溢出发生的区域

5内存溢出异常 6内存溢出常见原因 7发生内存泄露的情形Java内存泄露根本原因是什么呢?

答:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。 具体主要有如下几大类: 7.1 静态集合类引起内存泄露 像HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,他们所引用的所有的对象Object也不能被释放,因为他们也将一直被Vector等引用着。 例: 解析: 在这个例子中,循环申请Object 对象,并将所申请的对象放入一个Vector 中,如果仅仅释放引用本身(o=null),那么Vector 仍然引用该对象,所以这个对象对GC 来说是不可回收的。因此,如果对象加入到Vector 后,还必须从Vector 中删除,最简单的方法就是将Vector对象设置为null。 7.2创建过大对象

以上代码运行时瞬间报错。 7.3监听器 在java 编程中,我们都需要和监听器打交道,通常一个应用当中会用到很多监听器,我们会调用一个控件的诸如addXXXListener()等方法来增加监听器,但往往在释放对象的时候却没有记住去删除这些监听器,从而增加了内存泄漏的机会。 7.4 各种连接 比如数据库连接(dataSourse.getConnection()),网络连接(socket)和io连接,除非其显式的调用了其close()方法将其连接关闭,否则是不会自动被GC 回收的。对于Resultset 和Statement 对象可以不进行显式回收,但Connection 一定要显式回收,因为Connection 在任何时候都无法自动回收,而Connection一旦回收,Resultset 和Statement 对象就会立即为NULL。但是如果使用连接池,情况就不一样了,除了要显式地关闭连接,还必须显式地关闭Resultset Statement 对象(关闭其中一个,另外一个也会关闭),否则就会造成大量的Statement 对象无法释放,从而引起内存泄漏。这种情况下一般都会在try里面去的连接,在finally里面释放连接。 7.5 内部类和外部模块等的引用 内部类的引用是比较容易遗忘的一种,而且一旦没释放可能导致一系列的后继类对象没有释放。此外程序员还要小心外部模块不经意的引用,例如程序员A 负责A 模块,调用了B 模块的一个方法如: public void registerMsg(Object b); 这种调用就要非常小心了,传入了一个对象,很可能模块B就保持了对该对象的引用,这时候就需要注意模块B 是否提供相应的操作去除引用。 7.6 单例模式 不正确使用单例模式是引起内存泄露的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露

java内存空间详解

硬盘 heap stack Data code 内存 程序 操作系统代码 程序代码 New ,在堆里面为属性分配空间,初始化(String 默认值为null ) 声明的时候非配空间,初始值为null (局部变量,方法参数) 全局变量 存放程序所需要的代码 类变量,全局字符串,常量存放在数据段

Java内存分配与管理是Java的核心技术之一,之前我们曾介绍过Java的内存管理与内存泄露以及Java垃圾回收方面的知识,今天我们再次深入Java核心,详细介绍一下Java 在内存分配方面的知识。一般Java在内存分配时会涉及到以下区域: ◆寄存器:我们在程序中无法控制 ◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 ◆堆:存放用new产生的数据 ◆静态域:存放在对象中用static定义的静态成员 ◆常量池:存放常量

◆非RAM存储:硬盘等永久存储空间 Java内存分配中的栈 在函数中定义的一些基本类型的变量数据和对象的引用变量都在函数的栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。 Java内存分配中的堆 堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。 在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。引用变量就相当于是为数组或者对象起的一个名称。 引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。这也是Java 比较占内存的原因。 实际上,栈中的变量指向堆内存中的变量,这就是Java中的指针! 常量池(constant pool) 常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值(final)还包含一些以文本形式出现的符号引用,比如: ◆类和接口的全限定名; ◆字段的名称和描述符; ◆方法和名称和描述符。 虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和floating point常量)和对其他类型,字段和

今咱们来聊聊JVM 堆外内存泄露的BUG是如何查找的

今咱们来聊聊JVM 堆外内存泄露的BUG是如何查找的 前言JVM的堆外内存泄露的定位一直是个比较棘手的问题。此次的Bug查找从堆内内存的泄露反推出堆外内存,同时对物理内存的使用做了定量的分析,从而实锤了Bug的源头。笔者将此Bug分析的过程写成博客,以飨读者。由于物理内存定量分析部分用到了linux kernel虚拟内存管理的 知识,读者如果有兴趣了解请看ulk3(《深入理解linux内核第三版》)内存泄露Bug现场一个线上稳定运行了三年的系统,从物理机迁移到docker环境后,运行了一段时间,突然被监控系统发出了某些实例不可用的报警。所幸有负载均衡,可以自动下掉节点,如下图所示:登录到对应机器上后,发现由于内存占用太大,触发OOM,然后被linux系统本身给kill了。应急措施紧急在出问题的实例上再次启动应用,启动后,内存占用正常,一切Okay。奇怪现象当前设置的最大堆内存是1792M,如下所示:-Xmx1792m -Xms1792m -Xmn900m -XX:PermSi ze=256m -XX:MaxPermSize=256m -server -Xss512k查看操作系统层面的监控,发现内存占用情况如下图所示:上图蓝色的线表示总的内存使用量,发现一直涨到了4G后,超出了系统限制。很明显,有堆外内存泄露了。推荐一个交流学习群:478030634里面会分享一些资深架构师录制的视频录像:有

Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多:查找线索gc日志一般出现内存泄露,笔者立马想到的就是查看当时的gc日志。本身应用所采用框架会定时打印出对应的gc日志,遂查看,发现gc日志一切正常。对应日志如下:查看了当天的所有gc日志,发现内存始终会回落到170M左右,并无明显的增加。要知道JVM进程本身占用的内存可是接近4G(加上其它进程,例如日志进程就已经到4G了),进一步确认是堆外内存导致。排查代码打开线上服务对应对应代码,查了一圈,发现没有任何地方显式利用堆外内存,其没有依赖任何额外的native方法。关于网络IO的代码也是托管给Tomcat,很明显,作为一个全世界广泛流行的Web服务器,Tomcat不大可能有堆外内存泄露。进一步查找由于在代码层面没有发现堆外内存的痕迹,那就继续找些其它的信息,希望能发现蛛丝马迹。Dump出JVM的Heap堆由于线上出问题的Server已经被kill,还好有其它几台,登上去发现它们也占用了很大的堆外内存,只是还没有到触发OOM 的临界点而已。于是就赶紧用jmap dump了两台机器中应用JVM的堆情况,这两台留做现场保留不动,然后将其它机器迅速重启,以防同时被OOM导致服务不可用。使用如下命令dump:jmap -dump:format=b,file=heap.bin [pid]使用MAT

apache服务器出现内存溢出的解决方法

apache服务器出现内存溢出的解决方法 2011-10-08 14:26 Tomcat内存溢出的原因 在生产环境中tomcat内存设置不好很容易出现内存溢出。造成内存溢出是不一样的,当然处理方式也不一样。 这里根据平时遇到的情况和相关资料进行一个总结。常见的一般会有下面三种情况: 1.OutOfMemoryError: Java heap space 2.OutOfMemoryError: PermGen space 3.OutOfMemoryError: unable to create new native thread. Tomcat内存溢出解决方案 对于前两种情况,在应用本身没有内存泄露的情况下可以用设置tomcat jvm参数来解决。(-Xms -Xmx -XX:PermSize -XX:MaxPermSize) 最后一种可能需要调整操作系统和tomcat jvm参数同时调整才能达到目的。 第一种:是堆溢出。 原因分析: JVM堆的设置是指java程序运行过程中JVM可以调配使用的内存空间的设置.JVM在启动的时候会自动设置Heap size的值,其初始空间(即-Xms)是物理内存的1/64,最大空间(-Xmx)是物理内存的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等选项可进行设置。Heap size 的大小是Young Generation 和Tenured Generaion 之和。 在JVM中如果98%的时间是用于GC且可用的Heap size 不足2%的时候将抛出此异常信息。 Heap Size 最大不要超过可用物理内存的80%,一般的要将-Xms和-Xmx选项设置为相同,而-Xmn为1/4的-Xmx值。 没有内存泄露的情况下,调整-Xms -Xmx参数可以解决。 -Xms:初始堆大小 -Xmx:最大堆大小 但堆的大小受下面三方面影响:

内存溢出和内存泄漏的区别

内存溢出和内存泄漏的区别(内存泄漏原因) 内存溢出out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。 内存泄露memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。 memory leak会最终会导致out of memory! 内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。 内存泄漏是指你向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果你申请到的那块内存你自己也不能再访问(也许你把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。一个盘子用尽各种方法只能装4个果子,你装了5个,结果掉倒地上不能吃了。这就是溢出!比方说栈,栈满时再做进栈必定产生空间溢出,叫上溢,栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列,称为内存溢出. 以发生的方式来分类,内存泄漏可以分为4类: 1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。 2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。 3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。 4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。 从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。

内存泄露测试方法

如何测试客户端软件的内存泄露客户端软件包括C/S系统的客户端和B/S系统中的客户端控件,当用户使用客户端软件时,如果发现我们的软件会吃内存,那是很丢面子的事,有哪些好的测试方法呢?希望大家能踊跃提出自己的看法。 会员huior的精彩回答:如何发现客户端软件中的内存泄露?我的看法是:检测内存泄漏的问题应该尽早进行,它绝不应该是系统测试时的主要目标。也就是说,检查是否存在内存泄漏,应该从编码时就要考虑,单元测试和集成测试时要重点检查。如果前期没有考虑,等到了系统测试才想起检查或者才发现泄漏,为时已晚,此时再去定位泄漏的位置,太难太难了,它可能会让你的交付日期delay不确定的时间。 最近看了一些自动错误预防(AEP)的理论,我深受启发。作为测试人员的我们,从“发现错误”转变到“帮助开发人员预防错误”,这将是一个巨大的转变。所以说,下面我的答案中的第一点,我先说如何预防内存泄漏的问题,然后再讲如何发现。如何在开发过程中有效预防内存泄漏? 第一步:遵循“好”的编程规则“好”的编程规则是各位前辈经验和教训的集合,好的编程规则堪称开发者的“圣经”。遵循统一的编程规则,可以让开发新手少走好多弯路,可以让项目整体的质量维持一个起码的“质量底线”。有关内存泄漏方面的规则主要是“内存管理”方面的,举几个简单的,如下x用malloc或new申请内存之后,立即检查指针值是否为NULL(防止使用指针值为NULL的内存),×动态内存的申请与释放是否配对(防止内存泄漏),x malloc 语句是否正确无误?例如字节数是否正确?类型转换是否正确×是否出现野指针,例如用free或delete释放了内存之后,忘记将指针设置为NULL。 第二步:积极主动检测“内存泄漏”,严格遵循好的编程规则,可以让程序员在代码中尽量少的引入bug,但一旦不小心引入了,怎么办?这就要求我们在单元测试和集成测试中严格把关。在这个阶段,单靠程序员或者测试员通过“代码走查”的方式检查内存泄漏,客户的实践和我的经验告诉我,这是不切实际的,无论效率还是时间。如果能够借助于一些专业的工具的话,情况可能就不一样了。 如果你的程序是用Visual C++ 6.0开发,那么Numega的BoundsChecker将是你检测“内存泄漏”最好的选择,如果是Visual C++.NET,可以试一下Compuware的DevPartner。如果你的程序基于Unix或者Linux平台,使用C或者C++,可以考虑一下开源的工具valgrind,我的朋友跟我说,它在一定程度上比Rational的Purify更出色。上面的工具都要求程序能够动态运行起来,而且测试用例需要你自己准备。 如果你正处于单元测试或集成测试阶段,程序代码量已经足够大,而且还不能够动态运行,要尽早检测代码中的“内存泄漏”问题,该怎么办?此时你可以试用一下目前最新的静态分析技术:×它不要求代码能够动态运行,×也不需要你来编写测试用例,×只需要代码能够正常编译,就可以发现代码只有在执行过程中才出现的错误,当然也包括内存泄漏。 这方面的工具有Klocwork的K7,Coverity的SQS,以及C++test中的BugDetective,其中最“物美价廉”的就是c++test的BugDetective。 如何发现客户端软件的“内存泄漏”?如果开发过程中已经按照我上面提到的去做,相信发布后的程序存在“内存泄漏”的可能性几乎为零。如果开发过程已经到了后期,系统测试已经开始做了,还要发现内存泄漏,这个时候我希望你能够拿到源代码。如果有源代码,你还可以考虑第二步,借助专业的工具协助,虽然可能效果不一定特别理想,但总比下面我提到的方法更好一些。 当然作为测试人员,通常会碰到“需要在系统测试阶段检测是否有内存泄漏,而且没有

Java内存泄露模拟及分析解决方法

derwee Java内存泄露模拟及分析解决方法 1.1 实践目标: 1、使用JA V A代码实现模拟内存溢出 2、分析JDK内存溢出的原因 3、总结存在bug的JA V A编码实践 4、总结JVM优化的方法 1.2 模拟内存溢出: 为了方便模拟内存,特意把JVM的内存参数指定为更小(我的本本内存是8G的)。修改eclipse参数文件调用JVM参数: -vmargs -Xms40m(原始是-Xms40m) -Xmx100m(原始是-Xmx384m) 演示JA V A小程序实现原理:使用集合类对象装载大量的Persion对象,每次把new出来的对象加入集合类对象后,更改对象的属性,再从集合类对象中删除该对象。会出现该删除的对象没有被删掉,Persion类对象不断占用内存,导致分配给JVM的内存被耗光。 package .*; /** * * @ClassName: OutOfMemory * @Description: 内存溢出模拟,提出解决方法 * @author yangdw * @date 2012-3-25 下午6:58:49 */ public class OutOfMemory { public static void main(String[] args) { Collection collection = new HashSet(); for(int i=0;i<0;i++) { Persion per = new Persion(i,"yangdw"); (per);

1.2.1equals和hashcode重写原则[2] 1.2.1.1 对equals()应该遵循如下要求 1)对称性:如果(y)返回是“true”,那么(x)也应该返回是“true”。 2)自反性:(x)必须返回是“true”。 3)传递性:如果(y)返回是“true”,而且(z)返回是“true”,那么(x)也应该 返回是“true”。 4)任何情况下,(null),永远返回是“false”。 5)(和x不同类型的对象)永远返回是“false”。 1.2.1.2 hashCode()的返回值和equals()的关系如下 1)如果(y)返回“true”,那么x和y的hashCode()必须相等。 2)如果(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不 等。

Js内存泄漏及解决方案

在IE下的JS编程中,以下的编程方式都会造成即使关闭IE也无法释放内存的问题,下面分类给出: 1、给DOM对象添加的属性是一个对象的引用。范例: var MyObject = {}; document.getElementById('myDiv').myProp = MyObject; 解决方法: 在window.onunload事件中写上: document.getElementById('myDiv').myProp = null; 2、DOM对象与JS对象相互引用。范例: function Encapsulator(element) { this.elementReference = element; element.myProp = this; } new Encapsulator(document.getElementById('myDiv')); 解决方法: 在onunload事件中写上: document.getElementById('myDiv').myProp = null; 3、给DOM对象用attachEvent绑定事件。范例: function doClick() {} element.attachEvent("onclick", doClick); 解决方法: 在onunload事件中写上: element.detachEvent('onclick', doClick); 4、从外到内执行appendChild。这时即使调用removeChild也无法释放。范例: var parentDiv = document.createElement("div"); var childDiv = document.createElement("div"); document.body.appendChild(parentDiv); parentDiv.appendChild(childDiv); 解决方法: 从内到外执行appendChild: var parentDiv = document.createElement("div"); var childDiv = document.createElement("div"); parentDiv.appendChild(childDiv);

内存泄露和内存溢出的区别

内存泄漏是指分配出去的内存无法回收了 内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。 一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显示释放的内存。应用程序一般使用malloc,realloc,new等函数从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,否则,这块内存就不能被再次使用,我们就说这块内存泄漏了。 内存泄漏分类 1.常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。2.偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。3.一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块且仅一块内存发生泄漏。比如,在一个Singleton类的构造函数中分配内存,在析构函数中却没有释放该内存。而Singleton类只存在一个实例,所以内存泄漏只会发生一次。4.隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。 下面给出了一个简单的内存泄露的例子。在这个例子中,我们循环申请Object对象,并将所申请的对象放入一个Vector中,如果我们仅仅释放引用本身,那么Vector仍然引用该对象,所以这个对象对GC来说是不可回收的。因此,如果对象加入到Vector后,还必须从Vector中删除,最简单的方法就是将Vector对象设置为null。 Vector v=new Vector(10); for(int i=1;i<100;i++) { Object o=new Object(); v.add(o); o=null;

相关文档
最新文档