Java异常实战——OutOfMemoryError
在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的更多相关文章
- java异常面试常见题目
在Java核心知识的面试中,你总能碰到关于 处理Exception和Error的面试题.Exception处理是Java应用开发中一个非常重要的方面,也是编写强健而稳定的Java程序的关键,这自然使它 ...
- Java 异常讲解(转)
六种异常处理的陋习 你觉得自己是一个Java专家吗?是否肯定自己已经全面掌握了Java的异常处理机制?在下面这段代码中,你能够迅速找出异常处理的六个问题吗? 1 OutputStreamWrite ...
- 关于Java异常和错误的几个问题
1.Java中什么是Exception? 异常是Java传达给你的系统和程序错误的方式. 在java中,异常功能是通过实现比如Throwable,Exception,RuntimeException之 ...
- 一篇不错的讲解Java异常的文章(转载)
http://www.blogjava.net/freeman1984/archive/2007/09/27/148850.html 六种异常处理的陋习 你觉得自己是一个Java专家吗?是否肯定自己已 ...
- Java异常错误的面试题及答案
1) Java中什么是Exception? 这个问题经常在第一次问有关异常的时候或者是面试菜鸟的时候问.我从来没见过面高级或者资深工程师的 时候有人问这玩意,但是对于菜鸟,是很愿意问这个的.简单来说, ...
- 全面理解Java异常的运行机制
1. 引子 try…catch…finally恐怕是大家再熟悉不过的语句了,而且感觉用起来也是很简单,逻辑上似乎也是很容易理解.不过,我亲自体验的“教训”告诉我,这个东西可不是想象中的那么简单.听话. ...
- Java异常基础Exception
异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通 过API中Throwable类的众多子类描述各种不同的异常. ...
- Java异常的正确使用姿势
最近在项目代码中,遇见异常滥用的情形,会带来什么样的后果呢? 1. 代码可读性变差,业务逻辑难以理解 异常流与业务状态流混在一起,无法从接口协议层面理解业务代码,只能深入到方法(Method)内部才能 ...
- java异常常见面试问题
java异常常见面试问题 一.java异常的理解 异常主要是处理编译期不能捕获的错误.出现问题时能继续顺利执行下去,而不导致程序终止,确保程序的健壮性. 处理过程:产生异常状态时,如果当前的conte ...
随机推荐
- java 理解如何实现图片验证码 傻瓜都能看懂。
先代码后解释: 只要把代码复制到你的项目中就可以了. 代码: 验证码工具类: package cn.happy.util.imagesVerTion; /** * Author: SamGroves ...
- SQL优化 MySQL版 - B树索引详讲
SQL优化 MySQL版 - -B树索引详讲 作者:Stanley 罗昊 [转载请注明出处和署名,谢谢!] 为什么要进行SQL优化呢?很显然,当我们去写sql语句时: 1会发现性能低 2.执行时间太 ...
- 粮草先行——Android折叠屏开发技术点(二)
继该系列的第一篇和番外篇之后,今天我们来聊一聊多窗口开发的注意事项.实际上,与其说"多窗口开发",不如说让我们的APP适应多窗口模式. 可能有朋友会问,为什么要提到多窗口模式呢? ...
- 设计模式 | 观察者模式/发布-订阅模式(observer/publish-subscribe)
定义: 定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己. 结构:(书中图,侵删) 一个抽象的观察者接口, ...
- Git原理与命令大全
Git (wiki: en chs )是一个免费开源的分布式版本控制系统,由linux内核作者linus Torvalds开发,大型开源项目linux kernel.Android.chromium ...
- MySQL 文章目录
MySQL系列: MySQL CREATE TABLE语法 MySQL 复制表结构 MySQL 对比数据库表结构 MySQL 处理插入过程中的主键唯一键重复值办法 MySQL 启动原理剖析 MySQL ...
- 【从零开始搭建自己的.NET Core Api框架】(七)授权认证进阶篇
系列目录 一. 创建项目并集成swagger 1.1 创建 1.2 完善 二. 搭建项目整体架构 三. 集成轻量级ORM框架——SqlSugar 3.1 搭建环境 3.2 实战篇:利用SqlSuga ...
- Java笔试题库之选题题篇【71-140题】
71下面哪几个函数是public void method(){̷}的重载函数?() A.public void method( int m){̷} B.public int method(){̷} C ...
- Java中Map和Object的互相转换方式
一.使用Apache中的BeanUtils类,导入commons-beanutils包. Jar包Maven下载地址:https://mvnrepository.com/artifact/common ...
- 【机器学习】--Python机器学习库之Numpy
一.前述 NumPy(Numerical Python的缩写)是一个开源的Python科学计算库.使用NumPy,就可以很自然地使用数组和矩阵. NumPy包含很多实用的数学函数,涵盖线性代数运算.傅 ...