全部博文(70)
分类:
2009-04-08 09:40:41
:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://itsxhu.blogbus.com/logs/21994494.html
OutOfMemory问题解决方法
前段时间负责的系统出现多次OutOfMemory问题,在解决这个问题总看过了非常多的文档,对于这个问题的解决也有了一点自己的认识。今天将其总结一下,希望对其它碰到相同问题的朋友能有一些启示。
系统出来OufOfMemory问题的原因有很多种,首先需要根据出现OutOfMemory时打印的日志来分析出现这个的原因,然后根据分析结果选择对应的策略。在分析日志之前需要对JVM内存管理有一个比较深刻的认识,这样才能明白到底是哪个地方出了问题。下面是摘自Memory Management white paper(这份文档在SUN官方网站有下载,值得一看)的一段描述:
•Java heap space
This indicates that an object could not be allocated in the heap. The issue may be just a configuration
problem. You could get this error, for example, if the maximum heap size specified by the –Xmx
command line option (or selected by default) is insufficient for the application. It could also be an
indication that objects that are no longer needed cannot be garbage collected because the
application is unintentionally holding references to them. The HAT tool (see Section 7) can be used to
view all reachable objects and understand which references are keeping each one alive. One other
potential source of this error could be the excessive use of finalizers by the application such that the
thread to invoke the finalizers cannot keep up with the rate of addition of finalizers to the queue. The
jconsole management tool can be used to monitor the number of objects that are pending
finalization.
• PermGen space
This indicates that the permanent generation is full. As described earlier, that is the area of the heap
where the JVM stores its metadata. If an application loads a large number of classes, then the
permanent generation may need to be increased. You can do so by specifying the command line
option –XX:MaxPermSize=n, where n specifies the size.
• Requested array size exc-Xloggc:
This indicates that the application attempted to allocate an array that is larger than the heap size. For
example, if an application tries to allocate an array of 512MB but the maximum heap size is 256MB,
then this error will be thrown. In most cases the problem is likely to be either that the heap size is too
small or that a bug results in the application attempting to create an array whose size is calculated to
be incorrectly huge.
一般出现比较多的是Heap空间不足导致OutOfMemory,这时的报错提示是java.lang.OutOfMemoryError: Java heap space,这种情况下只需要在程序启动时调整一下内存就行,调整的方式是用-Xms -Xmx参数。这个可能参照Eclipse启动时的那一串参数,不过我指的是在Windows下面,Linux下面还没找到这个启动的参数。
另外一种情况是出现java.lang.OutOfMemoryError: PermGen space的异常。这种异常的原因是PermGen区内存不足,需要解决这个问题你就需要对JVM里面对内存的管理比较熟悉了。在JVM中这个PermGen区是存放所有装载了到系统中的class,interface的meta data的。这时用–XX:MaxPermSize=n来改变PermGen的大小,找到一个适当的大小就能解决这个问题了。
第三种情况是申请的内存空间的大小走过了JVM所能提供的大小,或者是申请一块大内存区域分配内存时没有连续的内存,导致出现OutOfMemory。这种情况不是内存不够的问题,而是内存区中出现太多内存碎片导致无法分配大块内存,这时候需要GC来工作了。 关于GC的工作原理,以及每一种GC算法的策略可能参见相关JVM的文档,根据这个文档提供的策略进行的GC调优。 GC调优是一个非常大的概念,不同的情况采用的策略大不相同,需要针对系统进行大量的分析。
GC调优的一些基本做法是先将GC的日志打印出来进行分析,首先确认是否是代码层存在内存泄漏问题。通过在启动时设置-Xloggc:
还有一些情况的OufOfMemory非常奇怪,出现这类情况时打印的日志只有OutOfMemoryError: unable to create new native thread这个异常。这种情况是最麻烦的,需要解决这个问题需要对JVM规范中关于java thread有所了解。 在JVM中每创建一个线程时都会在OS级创建相应的对应线程,但是不一定是1:1的关系,这个涉及到JVM的thread model的问题,目前找到的资源料中显示在Solaris sparc中存在N:M和1:1模型可选择。回到正题,当JVM中在分配线程时发现OS中已经没有足够的线程来创建其相应的OS级对应线程就可能会出现这种问题。这时解决的方法是减小JVM中申请创建的线程数,让OS拥有更多的内存来创建新的线程,在前面一篇文章就有提到的heap的内存不能超过物理内存的1/4。
如果采用了所有以上策略还是没有找到解决方法的朋友,那么恭喜你,你可能发现了JVM的一个Bug。给Sun或者相应的JVM开发商报告并寻求解决方案吧。
最后再一次建议遇到这种问题的朋友请认真阅读一下SUN官方给出的Memory Management in the Java HotSpot Virtual Machine,其下载地址如下:java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf