为了账号安全,请及时绑定邮箱和手机立即绑定

解决Java OutOfMemory 问题的思考

标签:
Java

java.lang.OutOfMemoryError 是 java.lang.VirtualMachineError 的子类,当JVM由于内存不足而无法分配对象,并且垃圾收集器无法提供更多内存时, 会抛出这种异常.

虚拟机可能构造OutOfMemoryError 这个对象, 就好像堆栈不可写或者suppression被禁了一样.

OutOfMemoryError的类型:

有两类的OutOfMemory:
The java.lang.OutOfMemoryError: Java heap space
The java.lang.OutOfMemoryError: PermGen space

虽然这两种情况都是由于JVM耗尽了内存而发生的,但是它们彼此之间是非常不同的,并且它们的解决方案是相互独立的。

源码分析:

public class OutOfMemoryError extends VirtualMachineError {
    private static final long serialVersionUID = 8228564086184010517L;

    /**
     * Constructs an {@code OutOfMemoryError} with no detail message.
     */
    public OutOfMemoryError() {
        super();
    }

    /**
     * Constructs an {@code OutOfMemoryError} with the specified
     * detail message.
     *
     * @param   s   the detail message.
     */
    public OutOfMemoryError(String s) {
        super(s);
    }
}

我们可以看到, OutOfMemoryError 有两个构造函数, 一个是无参数的,一个是带一个详细消息的构造函数.

重现"java.lang.OutOfMemoryError: Java heap space"

下面一段代码,可以重现OutOfMemory:

package com.xqljj.outOfmem;
public class OutOfMemoryErrorExample {
 
    public static void main(String[] args) {
        StringBuffer str=new StringBuffer("initial");
        
        while(true)
        {
        	StringBuffer addbuffer = new StringBuffer("1234567890");
            str.append(addbuffer);
            System.out.println(" str length:"+str.length());
        }
    }
}

运行这个程序, 会出现如下的问题:

0 str length:609221753
0 str length:609222316
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Unknown Source)
	at java.lang.AbstractStringBuilder.expandCapacity(Unknown Source)
	at java.lang.AbstractStringBuilder.ensureCapacityInternal(Unknown Source)
	at java.lang.AbstractStringBuilder.append(Unknown Source)
	at java.lang.StringBuffer.append(Unknown Source)
	at com.xqljj.outOfmem.OutOfMemoryErrorExample.main(OutOfMemoryErrorExample.java:11)

在上面的例子中,我们可以看到一个小程序就可以创建OutOfMemoryError,因为只是小的错误步骤。因为它有无限循环,不断地在同一个变量上添加。

java.lang.OutOfMemoryError: Java heap space 的解决办法

比较简单的解决办法是: 调节JVM的参数, 增加最大堆的大小: 设置 -Xmx 和 -Xms 比例按照 1:1 或者1:1.5 例如:

export JVM_ARGS=”-Xms1024m -Xmx1024m”

如果调节了大小后,还会出现OutOfMemory, 我们就需要用相应的工具来调研内存泄漏问题, 分析程序的Heap Dump文件.

常用的工具是:
Eclipse Memory Analyzer(MAT) 分析Heap Dump
Profiler like Netbeans or JProbe.

java.lang.OutOfMemoryError: PermGen space的原因

产生PermGen space 问题的原因主要有二:

一. 我们通常知道 JVM采用分代垃圾回收, 分为新生代, 年老代和持久代. PermGen是持久代, 所以持久代是用来存储JVM
class, method相关的各种String Pool, 各种元数据.

大多数情况下, 持久代的默认size是大约64MB, 那么,实际中, 这个值是容易达到的.
那么我们就需要调节这个参数的值:

我们设置XMX, 并不能解决这个问题, 需要设置 “-XX: PermSize” and “-XX: MaxPermSize”

例如:
export JVM_ARGS=”-Xmx1024m -XX:MaxPermSize=256m”

二. 第二个原因是: ClassLoader 产生的内存泄漏. 一般情况下, 这个错误会发生在 GlassFish, Tomcat
等web server里面.

在应用服务器中使用不同的类加载器来加载不同的应用程序,以便在不影响同一服务器上其他应用程序的情况下部署和卸载一个应用程序。但是在卸载过程中,如果容器以某种方式保持对应用程序类加载器加载的任何类的引用,那么如果多次部署和卸载应用程序,该类和所有相关的类将不会被垃圾收集并快速填充permGen空间。

java.lang.OutOfMemoryError: PermGen space 的解决办法

正如上面所述, 第一个解决办法是调节参数,

export JVM_ARGS=”-XX:PermSize=64M -XX:MaxPermSize=256m”

当然, 如果同样的问题还会出现的话, 就需要具体分析下内存的泄漏情况了.
常用的工具是:
Eclipse Memory Analyzer(MAT) 分析Heap Dump
Profiler like Netbeans or JProbe.

以上,内存泄露分析和解决,供参考。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消