在Java虚拟机规范描述中,除了程序计数器外,虚拟机内存的其他几个运行区域都有发生 OOM 异常的可能。在这里,用代码验证各个运行时区域存储的内容并讨论该如何进行处理

Java堆溢出

Java 堆用于存储对象实例,只要不断创建对象,并且保证 GC Roots 到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么对象数量达到最大堆的容量限制之后就会产生内存溢出异常。

异常再现

代码采用如下虚拟机参数:

-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

这样 Java 堆的大小将被限制为20 MB 且不可拓展。通过参数 -XX:+HeapDumpOnOutOfMemoryError 可以让虚拟机在出现内存溢出异常时 Dump 出当前的内存堆转储快照以便时候进行分析。

采用如下代码进行验证:

public class HeapOOM {

	static class OOMObject {
} public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>(); while (true) {
list.add(new OOMObject());
}
}
}

运行结果:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid3460.hprof ...
Heap dump file created [28199779 bytes in 0.237 secs]

解决方法

Java 堆内存的 OOM 异常是实际应用中常见的内存溢出异常情况,出现时往往会紧跟着提示“Java heap space”。

要解决这个区域的异常,一般的手段是先通过内存映像分析工具,比如 MAT ,确认到底是出现了内存泄漏还是内存溢出。

如果是内存泄漏,可以进一步通过工具查看泄漏对象到 GC Roots 的引用链,找到泄漏对象是通过怎样的途径和 GC Roots 相关联并导致垃圾收集器无法自动回收它们所占的空间。

如果不是内存泄漏,换而言之,内存中的对象确实还有必要存活着,那么就应当检查虚拟机的堆参数,与机器物理内存对比看是否还可以调大。从代码层面上看,是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期间的内存消耗。

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

由于在 HotSpot 虚拟机中并不区分虚拟机栈或者本地方法栈,因此对于 HotSpot 而言,虽然 -Xoss 参数存在,但是实际上是无效的,栈容量只由 -Xss 参数设定。

异常再现

在单线程下,代码采用如下的虚拟机参数:

-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 (Throwable e) {
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}

解决方法

如果使用虚拟机默认参数,栈深度在大多数情况下(因为每个方法压入栈的帧大小并不是一样的,所以只能说在大多数情况下)达到1000 ~ 2000 完全没有问题,对于正常的方法调用(包括递归),这个深度应该完全足够。

但是,如果是因为建立过多的线程导致内存溢出,在不能减少线程数或者更换64位虚拟机的情况下,就只能通过减少最大堆和减少栈容量来换取更多的线程。

本机直接内存溢出

DirectMemory 容量可以通过 -XX :MaxDirectMemorySize 指定,如果不指定,则默认与Java最大堆一样。

异常再现

使用以下虚拟机参数:

-Xmx20M -XX:MaxDirectMemorySize=10M

使用以下代码重现异常:

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);//直接申请分配内存
}
}
}

解决方法

由 DirectMemory 导致的内存溢出,一个明显的特征就是在Heap Dump 文件中不会看见明显的异常。

如果发现 OOM 之后Dump文件很小,而程序中又直接或者间接使用了NIO ,那么就可以考虑检查一下是不是这方面的原因。

Java异常实战——OutOfMemoryError的更多相关文章

  1. java异常面试常见题目

    在Java核心知识的面试中,你总能碰到关于 处理Exception和Error的面试题.Exception处理是Java应用开发中一个非常重要的方面,也是编写强健而稳定的Java程序的关键,这自然使它 ...

  2. Java 异常讲解(转)

    六种异常处理的陋习 你觉得自己是一个Java专家吗?是否肯定自己已经全面掌握了Java的异常处理机制?在下面这段代码中,你能够迅速找出异常处理的六个问题吗?   1 OutputStreamWrite ...

  3. 关于Java异常和错误的几个问题

    1.Java中什么是Exception? 异常是Java传达给你的系统和程序错误的方式. 在java中,异常功能是通过实现比如Throwable,Exception,RuntimeException之 ...

  4. 一篇不错的讲解Java异常的文章(转载)

    http://www.blogjava.net/freeman1984/archive/2007/09/27/148850.html 六种异常处理的陋习 你觉得自己是一个Java专家吗?是否肯定自己已 ...

  5. Java异常错误的面试题及答案

    1) Java中什么是Exception? 这个问题经常在第一次问有关异常的时候或者是面试菜鸟的时候问.我从来没见过面高级或者资深工程师的 时候有人问这玩意,但是对于菜鸟,是很愿意问这个的.简单来说, ...

  6. 全面理解Java异常的运行机制

    1. 引子 try…catch…finally恐怕是大家再熟悉不过的语句了,而且感觉用起来也是很简单,逻辑上似乎也是很容易理解.不过,我亲自体验的“教训”告诉我,这个东西可不是想象中的那么简单.听话. ...

  7. Java异常基础Exception

    异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通 过API中Throwable类的众多子类描述各种不同的异常. ...

  8. Java异常的正确使用姿势

    最近在项目代码中,遇见异常滥用的情形,会带来什么样的后果呢? 1. 代码可读性变差,业务逻辑难以理解 异常流与业务状态流混在一起,无法从接口协议层面理解业务代码,只能深入到方法(Method)内部才能 ...

  9. java异常常见面试问题

    java异常常见面试问题 一.java异常的理解 异常主要是处理编译期不能捕获的错误.出现问题时能继续顺利执行下去,而不导致程序终止,确保程序的健壮性. 处理过程:产生异常状态时,如果当前的conte ...

随机推荐

  1. MIP技术进展月报第2期: 数据绑定,异步脚本加速

    一. 功能更新 1. mip-bind 上线,实现复杂交互 MIP bind 双向绑定机制和组件上线,提供双向绑定的特性:能够允许页面实现数据驱动功能,开发者可以在任意场景修改数据,并驱动页面元素变动 ...

  2. FOFA爬虫大法——API的简单利用

    FOFA是一款网络空间搜索引擎,它通过进行网络空间测绘,帮助研究人员或者企业迅速进行网络资产匹配,例如进行漏洞影响范围分析.应用分布统计.应用流行度等. 何为API?如果你在百度百科上搜索,你会得到如 ...

  3. final 关键字与安全发布 多线程中篇(十三)

    final的通常理解 在Java中,final关键字可以用来修饰类.方法和变量(包括成员变量和局部变量) 大家应该都知道final表示最终的.最后的含义,也就是不能在继续 修饰类表示不能继承,修饰方法 ...

  4. 『Möbius函数与Möbius反演』

    Möbius函数 定义 设正整数\(n\)算数基本定理分解后为\(n=\prod_{i=1}^{k}p_i^{a_i}\),定义函数 \[ \mu(n)= \begin{cases} 0\ \ (\e ...

  5. 理解 Node.js 的 Event loop

    问题 考察如下代码,脑回路中运行并输出结果: console.log("1"); setTimeout(function setTimeout1() { console.log(& ...

  6. 微信小程序echarts层级太高

    项目中因为需求,底部的tab导航栏是自己写的,在开发者工具中一切正常:但是在真机上页面滑动时,echarts的层级比tab高,调过两者的z-index后仍然如此. 经过查找后发现cover-view和 ...

  7. 全球第一免费开源ERP Odoo PM OKR项目管理操作指南

    概览 ​ Odoo项目允许你和整个项目团队一起管理项目, 与项目和任务成员中的任何一个人沟通. 它与包含可定制阶段的任务的项目一起工作.项目可以是内部的或客户导向的.任务是项目执行的一部分.你可以给这 ...

  8. Python之路【第五篇】:Python基础之文件处理

    阅读目录 一.文件操作 1.介绍 计算机系统分为:计算机硬件,操作系统,应用程序三部分. 我们用python或其他语言编写的应用程序若想要把数据永久保存下来,必须要保存于硬盘中,这就涉及到应用程序要操 ...

  9. LogWriter: Operating system error 21(error not found) encountered

      一台老旧的数据库服务器(SQL Server 2005)突然报如下错误,而且数据库处于RECOVERY PENDING ,检查错误日志,发现这个错误是突然出现的.没有任何其它人为误操作导致 Dat ...

  10. java中强大的免费的集成开发环境(IDE)eclipse的使用技巧及注意事项

    1调整字体,window->prefernce->Appereance->colors and fonts->Basic->Text font双击即可进行编辑 2.设置行 ...