`
qqdwll
  • 浏览: 131229 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

转载 --- "JAVA内存泄漏"一个永恒的主题

    博客分类:
  • Java
阅读更多

  
内存不足与泄漏(OutOfMemoryError,以下简称OOM)的发生,就像系统的性能一样,对于JAVA开发人员来说是一个十分棘手的问题,也是让许多开发人员陷于束手无策的局面,而这两个问题却又时常困扰着每个JAVA软件系统。

本文主要来探讨关于JAVA内存泄漏的问题,首先简述JVM的基础概念,而后是关于西湖小学网站信息发布系统内存泄漏问题解决全过程的讲述。


JVM的内存管理


一、 相关概念

1. JAVA堆

JAVA堆指JVM用来存储分配 JAVA 对象的这部分内存。通过-Xmx参数设置JAVA 堆内存的最大值,-Xms参数设置堆内存的最小值。建议您指定最大的 JAVA 堆值,因为若未指定最大的堆大小,那么该极限值由 JVM 根据诸如计算机中的物理内存量和该时刻的可用空闲内存量这类因素来决定。


2. 本地内存(Permanent Generation)

本地内存指JVM用于其自身内部操作的内存,通常也称永久域。JVM 将使用的本地内存的大小取决于生成的代码量、创建的线程、GC 期间用于保存 java 对象信息的内存,以及在代码生成、优化等过程中使用的临时空间。如果有一个第三方本地模块,那么它也可能使用本地内存。例如,本地 JDBC 驱动程序将分配本地内存。

系统默认的永久域大小是4M,但可以通过设置参数-XX:PermSize以及-XX:MaxPermSize进行本地内存大小的修改。但最大的永久域大小受到任何特定操作系统上虚拟进程大小的限制,也受到用.Xmx标志指定用于 java 堆的内存量的限制。

3. 进程与线程

进程大小将是JAVA堆、本地内存与加载的可执行文件和库所占用内存的总和。在 32 位操作系统上,进程的虚拟地址空间最大可达到 4 GB。从这 4 GB 内存中,操作系统内核为自己保留一部分内存(通常为 1 - 2 GB),剩余内存可用于应用程序。

线程是一个进程中的一个子序列,由程序负责管理。对于每个操作系统而言,线程也是一种资源,对于允许线程数的多少也都有各自的定义。

4. JAVA堆的细分

JAVA堆还可细分为新域和旧域(New/Old Generation),JVM将生成的所有新对象放在新域中,在当对象经历了一定数量的垃圾收集循环后,便获得使用期并进入旧域。其中新域又可分成三个部分:第一部分为Eden Space,用于存放生成新的对象,另两部分都称为救助空间(Survivor Space)。当然具体对象的存放与特定的拉圾回收算法有着密切的相关。


二、 拉圾回收算法

当程序满足拉圾回收条件时,JVM开始以一定的回收算法进行无用对象内存的释放。一般JVM会采用多种的回收算法,同时对于不同的JVM所采用的回收算法也不同。拉圾回收算法主要有以下几种:(更多具体内容,请读者搜索相关资料)
    标记-清除收集器
    标记-压缩收集器
    复制收集器
    增量收集器
    分代收集器
    并发收集器
    并行收集器


三、 为什么发生OOM问题

为什么会发生OOM?主要大方向可归结于以下两方面,在文章的后面会有具体的一些实例分析。

1. JAVA堆中的内存不足

如果JVM不能在JAVA堆中获得更多内存来分配更多JAVA 对象,将会抛出 JAVA 内存不足 (JAVA OOM) 错误。如果JAVA堆充满了活动对象,并且 JVM 无法再扩展 java 堆,那么它将不能分配更多 JAVA 对象。

在这种情况下,JVM 让应用程序决定在抛出 java.lang.OutOfMemoryError 后该执行什么操作。例如,应用程序可以处理此错误,并决定以安全方式自行关闭或决定忽略此错误。如果应用程序不处理此错误,那么抛出此错误的线程将退出(如果您进行 java Thread Dump,那么将看不到该线程)。

在使用 Weblogic Server 的情况下,如果此错误是由某个执行线程抛出的,则会处理此错误并将其记录在日志中。如果连续抛出此错误,那么核心运行状况监视器线程将关闭 Weblogic Server。

2. 本地堆中的内存不足

如果JVM无法获得更多本地内存,它将抛出本地内存不足(本地OOM)的错误。当进程到达操作系统的进程大小限值,或者当计算机用完 RAM 和交换空间时,通常会发生这种情况。

当发生这种情况时,JVM处理本地OOM状态,记录它已用完本地内存或无法获得内存的消息,然后退出。如果JVM或使用本地内存的其它模块不处理这个本地OOM状态,那么操作系统将给JVM发送命令JVM退出的sigabort信号。通常情况下,JVM收到sigabort信号时将会生成一个核心文件,并退出。


西湖小学网站信息发布系统内存泄漏问题解决


一、 问题反馈

1. 系统背景

作为示范用户,西湖小学一直在使用网站等相关产品,公司对西湖小学的支持力度也比较大,2003年就定制了网站页面,作为示范网站进行宣传,04年11月进行升级改版,到05年4月份完成改版定型升级工作,现使用网站发布平台V3.5版本,在杭州有较大的影响力。

2. 问题描述

05年4月新版本上马后,一开始还比较稳定,大约两周左右才会出现网站不能访问的情况。一个多月后网站崩溃周期变短,学校把内存加到2G,我们重新设置了内存参数后,一般一周需要重启一次,后来随着访问量增大,越来越不稳定,需要两天重启一次。我们写了一个bat,让计划任务每天凌晨自动重启服务,但学校服务器禁止执行批处理。目前网站现象是每隔两天,就会出现网站不能访问,一般重启就可以解决。

另外,用户反应在系统后台信息管理的信息添加模块和类别添加模块,最容易系统当机。

3. 用户要求

用户只要求系统当机的周期能长一些,最好在两周以上即可。


二、 简单分析

1. 用户在2003年就开始使用信息发布系统,而只有在升级到3.5新版后才发现不稳定现象;

2. 访问量越大,系统当机时间缩短,当机的原因断定是与计算机资源相关;

3. 服务重启即可恢复正常,更加说明了是计算机资源问题,初步断定是内存泄漏所致;

三、 学习与监控全过程

1. 服务器当机的原因是由于OOM错误所致,故对用户服务器进行内存的定期监控。
由于一开始对一些工具使用的不熟悉,采用了人工监控;而后采用了windows自带的监控工具:控制面板>管理工具> 性能(或perfmon命令)。

2. 网上搜索相关资料,并学习阅读内存泄漏方面的文章。

3. 根据监测数据,初步认为是内存使用量不断增长所致。由于用户服务器内存较大,初步缓解的解决方案是调整用户服务器启动参数,增大应用服务器的可用内存量。

4. 设置参数后,系统运行两天左右仍存在当机现象,说明原因并未找到。

5. 测试部加入,准备采用Optimizeit专业检测工具进行测试。在检测工具使用前,先对测试环境进行了当机模拟的性能压力测试。

6. 对比不同类别的OOM

通过设置启动参数(-Xms -Xmx)的不同值所引发出来的OMM与在测试环境下产生的OOM略有不同,测试环境下的OOM有所不同,如下:
ava.lang.OutOfMemoryError
ava.lang.OutOfMemoryError: unable to create new native thread

7. 之后重心转至“unable to create new native thread”上,再经过多次测试验证,导致OOM的原因是由于JVM无法创建本地线程所致,而非实际意义上的内存不足问题上。

8. 找到原因 > 定位代码 > 问题解决;

四、 小结
导致JAVA的OOM问题可能存在的原因会有很多,我们在解决该问题前应对它有总体的了解,并排除各种因素,最终定位原因所在。以个人经验,原因主要有以下几种:

1. JVM本身问题
2. 相关参数设置不合理
3. 程序中使用资源的未关闭
4. 一些编码的不规范,对无用对象的引用
5. 海量数据的处理及缓存的使用

在对上述几种原因分析之前,应有对一些基本知识和概念的了解,详细见参考部分。另外,很重要的一点是:在发现OOM问题后,不要一味的认为就是内存不足(即内存泄漏)所致,而忽略了其它了资源不足的可能,正确的做法是应先要以程序所报的错误信息为依据,确定OOM类型,再做具体分析。在此次网站信息发布系统内存泄漏问题解决过程中,就走了类似的弯路。

以下是对上述五种原因的简单解决方案:
问题1
原因:此问题发生可能极小。
解决:一般掌握JVM拉圾回收(GC)的一些基础知识和理论,很容易排除此类问题。
问题2
原因:内存使用设置太小。
解决:同问题1解决方案相似。
问题3
原因:此问题是程序开发过程中开发人员最易犯的错误,也是OOM查找过程中较难解决的问题。相关资源如数据库连接、输入输出流、JMS消息发布、webservice远程调用等各种连接都存在资源关闭问题,若程序调用后不做关闭,可能发生不可预计的错误结果。

解决:对此类问题有两个切入点:
1. 已经发生OOM的程序:此类程序只要通过人工或工具进行问题重现性的确认,即可定位相关源代码并进行研读,一般即可解决;
2. 未发生OOM或难以重现的程序:只有通过一些专业检测工具进行检测(如:Borland Optimizeit Profiler、JProbe Profiler 、JRockit Memory Leak Detector等)来进行检测。难度较大,需对所使用的工具及相关基础理论有较深入的掌握。
问题4
原因:通过编码的不规范编写出“对无用对象的引用”的代码是存在可能的,但一般较难写出类似的代码;而对于问题3资源释放的问题则是开发人员最易犯的一种错误。
解决:与问题3解决方案一样。
问题5
原因:此类问题一般是在处理大批量数据时,没有采用分批处理,而导致一次性申请过多内存,引发JVM内存使用量不足的OOM错误。如Hibernate的使用过程中,在同一个sesion里,一次性从数据库读取海量数据,Hibernate的一级缓存并没法释放,则可能导致OOM错误。
解决:对此类问题有两个切入点
1. 根本解决方案:对海量数据进行分批处理,让一些内存对象得以回收;
2. 临时解决方案:通过加大 %JAVA_OPTS% 启动参数的内存使用量设置值,能有一定缓解能力。



本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/superben/archive/2006/04/07/653704.aspx
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics