当前位置: 代码网 > it编程>编程语言>Java > JAVA 聚焦 OutOfMemoryError 异常问题记录

JAVA 聚焦 OutOfMemoryError 异常问题记录

2025年04月27日 Java 我要评论
在 java 开发中,内存溢出异常是影响程序稳定性的关键问题。了解其原理和应对方法,对开发者至关重要。一、java 堆溢出原理java 堆用于存储对象实例。不断创建对象,且阻止垃圾回收器回收,对象数量

在 java 开发中,内存溢出异常是影响程序稳定性的关键问题。了解其原理和应对方法,对开发者至关重要。

一、java 堆溢出

原理

java 堆用于存储对象实例。不断创建对象,且阻止垃圾回收器回收,对象数量超出堆容量时,就会引发堆溢出。

示例代码

// vm args: -xmx20m -xms20m -xx:+heapdumponoutofmemoryerror
public class heapoom {
    static class oomobject {}
    public static void main(string[] args) {
        list<oomobject> list = new arraylist<>();
        while (true) {
            list.add(new oomobject());
        }
    }
}

解决思路

  • 利用内存映像分析工具(如 eclipse memory analyzer )分析堆转储快照。
  • 区分内存泄漏和内存溢出:若存在无用对象长期占用内存,是内存泄漏;若对象都有用但堆空间不足,可调整堆参数(-xmx 与 - xms ),并优化代码减少内存占用。

二、虚拟机栈和本地方法栈溢出

原理

  • 线程请求栈深度超虚拟机允许值,抛出stackoverflowerror 。
  • 虚拟机栈若支持动态扩展,扩展时内存申请失败,抛出outofmemoryerror (hotspot 不支持栈动态扩展 )。

示例代码

测试stackoverflowerror

// vm args: -xss128k
public class javavmstacksof {
    private int stacklength = 1;
    public void stackleak() {
        stacklength++;
        stackleak();
    }
    public static void main(string[] args) throws throwable {
        javavmstacksof oom = new javavmstacksof();
        try {
            oom.stackleak();
        } catch (exception e) {
            system.out.println("stack length:" + oom.stacklength);
            throw e;
        }
    }
}

测试大量线程导致内存溢出

// vm args: -xss2m
public class javavmstackoom {
    private void dontstop() {
        while (true) {}
    }
    public void stackleakbythread() {
        while (true) {
            thread thread = new thread(() -> dontstop());
            thread.start();
        }
    }
    public static void main(string[] args) throws throwable {
        javavmstackoom oom = new javavmstackoom();
        oom.stackleakbythread();
    }
}

解决思路

  • 出现stackoverflowerror 时,可根据错误堆栈分析递归调用等问题代码。
  • 对于大量线程导致的内存溢出,可减少线程数量、调整栈内存大小(-xss ),或升级 64 位虚拟机以获取更多内存。

三、方法区和运行时常量池溢出

原理

  • 方法区存储类信息、常量池等。运行时动态生成大量类(如使用 cglib ),会耗尽方法区空间。
  • 运行时常量池是方法区一部分,字符串操作(如string.intern() )不当,可能导致常量池溢出。

示例代码

方法区溢出测试(借助 cglib )

// vm args: -xx:permsize=10m -xx:maxpermsize=10m
import net.sf.cglib.proxy.enhancer;
import net.sf.cglib.proxy.methodinterceptor;
import net.sf.cglib.proxy.methodproxy;
public class javamethodareaoom {
    static class oomobject {}
    public static void main(string[] args) {
        while (true) {
            enhancer enhancer = new enhancer();
            enhancer.setsuperclass(oomobject.class);
            enhancer.setusecache(false);
            enhancer.setcallback(new methodinterceptor() {
                @override
                public object intercept(object obj, java.lang.reflect.method method, object[] args, methodproxy proxy) throws throwable {
                    return proxy.invokesuper(obj, args);
                }
            });
            enhancer.create();
        }
    }
}

运行时常量池溢出测试(string.intern()

// jdk 6 运行:-xx:permsize=6m -xx:maxpermsize=6m
// jdk 7及以上运行:-xmx6m
public class runtimeconstantpooloom {
    public static void main(string[] args) {
        string str1 = new stringbuilder("计算机").append("软件").tostring();
        system.out.println(str1.intern() == str1); 
        string str2 = new stringbuilder("ja").append("va").tostring();
        system.out.println(str2.intern() == str2); 
    }
}

解决思路

  • 方法区溢出时,调整方法区相关参数(如 jdk 8 前的 - xx:permsize 和 - xx:maxpermsize ,jdk 8 及以后的 - xx:metaspacesize 等 ),优化代码减少动态类生成。
  • 针对常量池溢出,合理使用string.intern() 方法,避免无意义的字符串入池操作。

四、直接内存溢出

原理

直接内存容量由-xx:maxdirectmemorysize 参数控制,默认与 java 堆最大值相同。直接或间接使用directbytebufferunsafe 等分配内存超出限制,会引发溢出。

示例代码

// vm args: -xmx20m -xx:maxdirectmemorysize=10m
import sun.misc.unsafe;
import java.lang.reflect.field;
public class directmemoryoom {
    private static final int _1mb = 1024 * 1024;
    public static void main(string[] args) throws exception {
        field unsafefield = unsafe.class.getdeclaredfields()[0];
        unsafefield.setaccessible(true);
        unsafe unsafe = (unsafe) unsafefield.get(null);
        while (true) {
            unsafe.allocatememory(_1mb);
        }
    }
}

解决思路

  • 合理设置-xx:maxdirectmemorysize 参数。
  • 排查代码中直接内存分配操作,如 nio 相关代码,确保内存分配合理。
ld.get(null);
while (true) {
unsafe.allocatememory(_1mb);
}
}
}

解决思路

- 合理设置`-xx:maxdirectmemorysize` 参数。
- 排查代码中直接内存分配操作,如 nio 相关代码,确保内存分配合理。

通过深入理解 java 内存溢出异常原理,结合具体代码示例和解决思路,开发者能更好地定位和解决内存问题,保障 java 程序稳定运行。

到此这篇关于java 聚焦 outofmemoryerror 异常问题记录的文章就介绍到这了,更多相关java outofmemoryerror 异常内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com