java中OOM错误解析(面试可以聊的东西)
嗯,生活加油鸭。。。。 实习中遇到OOM错误
GC overhead limit exceeded 问题,所以整理一下OOM异常问题:不对的地方请小伙伴留言^_^
先看一下“阿里的开发手册”对OOM的描述:
OOM,全称“Out Of Memory”,翻译成中文就是“内存用完了”意思就是说,当JVM因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时,就会抛出这个error(注:非exception,因为这个问题已经严重到不足以被应用处理)。
- 内存泄露:申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段内存就泄露了,因为申请者不用了,而又不能被虚拟机分配给别人用。
- 内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢出。
然后看一下《深入理解java虚拟机》中描述的OOM发生区域:
- 1)Java虚拟机栈:
描述Java方法执行的内存模型,与计数器一般,java虚拟机栈也是线程私有的,它的生命周期与线程相同,每个方法在执行的同时会创建一个栈帧,用于存储局部变量表,操作数栈,动态链表,方法出口等信息。每个方法从调用到执行完成过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。
- 局部变量表:存储了编译期可知的各种基本数据类型,对象的引用(reference类型,即指向对象起始地址的引用指针)和returnAddress类型(指向一条字节码指令的地址)。long与double类型数据会占用2个局部变量空间,其余的数据类型会占用一个,局部变量表所需要的内存空间在编译期完成分配,当进入一个方法时,方法在帧中分配的局部变量空间是完全确定的。在方法运行期不会改变局部变量表的大小。
在Java虚拟机规范中,如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常。如果虚拟机栈可以动态扩展,但扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
- 2)本地方法栈:
与虚拟机类似,区别是虚拟机栈为虚拟机执行的Java方法服务,而本地方法栈则是为虚拟机使用到的Native方法服务。也会抛出StackOverflowError异常,OutOfMemoryError异常
- 3)Java堆:
java 堆是虚拟机所管理的内存中最大的一块,java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建,唯一作用是用来存放对象实例,几乎所有的对象实例以及数组都要在堆上分配地址。
java堆是垃圾收集器管理的主要区域。也被称为GC堆。Java堆可以处于物理上不连续的内存空间,只用逻辑上连续即可,可以通过-Xmx和Xms控制。如果在堆中没有内存完成实例分配,并且堆中也无法扩展,会抛出OutOfMenory异常。
- 4)运行时常量池:
是方法区的一部分,Class文件中除了有类的版本,字段,方法,接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
运行时常量池对于Class文件常量池的一个特征是具备动态性,Java语言不要求常量一定是在编译期才产生,即并非预置入Class文件中的常量池的内容可以才能进入方法区运行时常量池,运行期也可以将新的常量放入池中,比如String的intern()方法。当常量池无法 在申请内存时会抛出OutOfMethodError异常。
之后看具体的实例:
一、Java堆溢出:
package com.company; import java.util.ArrayList;
import java.util.List; /**
* @Author: Liruilong
* @Date: 2019/7/13 10:03
* VM Args:-Xms20m -Xmx20m -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());
}
}
}
java.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid13048.hprof ...
Heap dump file created [29202866 bytes in 0.128 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3204)
at java.util.Arrays.copyOf(Arrays.java:3175)
at java.util.ArrayList.grow(ArrayList.java:246)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:220)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:212)
at java.util.ArrayList.add(ArrayList.java:443)
at com.company.HeapOOM.main(HeapOOM.java:19)
二、虚拟机栈和本地方法栈溢出:
package com.company; /**
* @Author: Liruilong
* @Date: 2019/7/13 18:00
* @VM Args: -Xss128k
*/
public class JavaVMStackSOF { private int stackLength = 1; public void stackLeng(){
stackLength++;
stackLeng();
} public static void main(String[] args)throws Throwable {
JavaVMStackSOF oom = new JavaVMStackSOF();
try{
oom.stackLeng();
}catch (Throwable throwable){
System.out.println("sstack length:"+oom.stackLength);
throw throwable;
}
} }
sstack length:1001
Exception in thread "main" java.lang.StackOverflowError
at com.company.JavaVMStackSOF.stackLeng(JavaVMStackSOF.java:13)
at com.company.JavaVMStackSOF.stackLeng(JavaVMStackSOF.java:14)
………………
三、方法区和运行时常量池溢出
String.intern()是一个Native方法,当字符串对象已经包含一个String的字符串引用时,则返回字符串的引用,反之,将字符串添加到常量池中,并发挥Sting对象的引用。
在JDK1.6之前的版本,由于常量池分配永久代中,所以可以通过限制方法区的大小来限制常量池容量。
package com.company; import java.util.ArrayList;
import java.util.List; /**
* @Author: Liruilong
* @Date: 2019/7/14 7:05
* VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
*/
public class RuntimConstantPoolOOM { public static void main(String[] args) {
// 使用List保持常量池的引用,避免Full GC回收常量池行为
List<String> list = new ArrayList<>();
int i = 0;
while (true){
list.add(String.valueOf(i++).intern());
}
}
}
最后看遇到的问题:

查了一下:
oracle官方给出了这个错误产生的原因和解决方法:
Exception in thread thread_name: java.lang.OutOfMemoryError: GC Overhead limit exceeded
Cause: The detail message "GC overhead limit exceeded" indicates that the garbage collector is running all the time and Java program is making very slow progress. After a garbage collection, if the Java process is spending more than approximately 98% of its time doing garbage collection and if it is recovering less than 2% of the heap and has been doing so far the last 5 (compile time constant) consecutive garbage collections, then a java.lang.OutOfMemoryError is thrown. This exception is typically thrown because the amount of live data barely fits into the Java heap having little free space for new allocations.
Action: Increase the heap size. The java.lang.OutOfMemoryError exception for GC Overhead limit exceeded can be turned off with the command line flag -XX:-UseGCOverheadLimit.
原因:
大概意思就是说,JVM花费了98%的时间进行垃圾回收,而只得到2%可用的内存,频繁的进行内存回收(最起码已经进行了5次连续的垃圾回收),JVM就会曝出ava.lang.OutOfMemoryError: GC overhead limit exceeded错误。
即 超出了GC开销限制。是JDK6新添的错误类型。是发生在GC占用大量时间为释放很小空间的时候发生的,是一种保护机制。一般是因为堆太小,导致异常的原因:没有足够的内存。

经过分析,我使用多线程的解析文件,解析的文件信息存放占用很大的内存,而使用时,我使用其中一小部分,但是整个内存被占用着,GC无法进行回收,所以会报错。我解决的问题是把需要的信息提取出来放到内存里。减少了对内存的使用。
解决方法:
- 1、增加heap堆内存。
- 增大堆内存 set JAVA_OPTS=-server -Xms512m -Xmx1024m -XX:MaxNewSize=1024m -XX:MaxPermSize=1024m
- 2、增加对内存后错误依旧,获取heap内存快照,使用Eclipse MAT工具,找出内存泄露发生的原因并进行修复。
- 3、优化代码以使用更少的内存或重用对象,而不是创建新的对象,从而减少垃圾收集器运行的次数。如果代码中创建了许多临时对象(例如在循环中),应该尝试重用它们。
- 4、除了使用命令-xms1g -xmx2g设置堆内存之外,尝试在启动脚本中加入配置:
在启动脚本中添加-XX:-UseGCOverheadLimit命令。这个方法只会把“java.lang.OutOfMemoryError: GC overhead limit exceeded”变成更常见的java.lang.OutOfMemoryError: Java heap space错误。
java中OOM错误解析(面试可以聊的东西)的更多相关文章
- 转:在java中使用dom4j解析xml
JAVA 使用Dom4j 解析XML Java DOM4J Parser - Parse XML Document Dom4j下载及使用Dom4j读写XML简介 在java中使用dom4j解析xml ...
- JAVA中生成、解析二维码图片的方法
JAVA中生成.解析二维码的方法并不复杂,使用google的zxing包就可以实现.下面的方法包含了生成二维码.在中间附加logo.添加文字功能,并有解析二维码的方法. 一.下载zxing的架包,并导 ...
- 沉淀再出发:java中线程池解析
沉淀再出发:java中线程池解析 一.前言 在多线程执行的环境之中,如果线程执行的时间短但是启动的线程又非常多,线程运转的时间基本上浪费在了创建和销毁上面,因此有没有一种方式能够让一个线程执行完自己的 ...
- java中static关键字解析
static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键字的用法和平常容易误解的地方,最后列 ...
- Java中的Html解析:使用jsoup
包:jsoup-1.10.2.jar import java.io.File; import java.io.IOException; import org.jsoup.Jsoup; import o ...
- java中采用dom4j解析xml文件
一.前言 在最近的开发中用到了dom4j来解析xml文件,以前听说过来解析xml文件的几种标准方式:但是从来的没有应用过来,所以可以在google中搜索dmo4j解析xml文件的方式,学习一下dom4 ...
- java中main函数解析(转载)
从写java至今,写的最多的可能就是主函数 public static void main(String[] args) {} 但是以前一直都没有问自己,为什么要这么写,因为在c语言中就没有这样子的要 ...
- Java中的框架基础面试知识
spring mvc 工作机制(原理): DispatcherServlet主要用作职责调度工作,本身主要用于控制流程 Spring mvc运行原理 1.springmvc将所有的请求都提交给Disp ...
- Java中volatile关键字解析
一.内存模型的相关概念 大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存 ...
随机推荐
- 网页中三角型的CSS实现
我们在使用CSS框架的时候,经常会用到下拉框组件,一般该组件里面有个下三角.很多网上用到三角形,如图所示,这个三角形是如何实现的呢? 1.使用CSS可以实现,先来复习一CSS盒子模型相关知识.给出如下 ...
- 0318 guava并发工具
并发是一个难题,但是可以通过使用强力简单的抽象来显著的简化,为了简化问题,guava扩展了Future接口,即 ListenableFuture (可以监听的Future).我强烈建议你在你的所有代码 ...
- kerberos系列之zookeeper的认证配置
本篇博客介绍配置zookeeper的kerberos配置 一.zookeeper安装 1.解压安装包和重命名和创建数据目录 tar -zxvf /data/apache-zookeeper-3.5.5 ...
- 基于 HTML5 WebGL 与 GIS 的智慧机场大数据可视化分析
前言:大数据,人工智能,工业物联网,5G 已经或者正在潜移默化地改变着我们的生活.在信息技术快速发展的时代,谁能抓住数据的核心,利用有效的方法对数据做数据挖掘和数据分析,从数据中发现趋势,谁就能做到精 ...
- Java分布式IP限流和防止恶意IP攻击方案
前言 限流是分布式系统设计中经常提到的概念,在某些要求不严格的场景下,使用Guava RateLimiter就可以满足.但是Guava RateLimiter只能应用于单进程,多进程间协同控制便无能为 ...
- MySQL 教程--检视阅读
MySQL 教程--检视阅读 准备:Windows 上安装 MySQL 教程地址,PHP语言基础 教程地址2 教程地址3,有讲数据库的备份和恢复 教程地址4,w3c.china,php基础,扩展阅读 ...
- flume面试题
1 你是如何实现Flume数据传输的监控的使用第三方框架Ganglia实时监控Flume. 2 Flume的Source,Sink,Channel的作用?你们Source是什么类型?1.作用 (1)S ...
- 一份精简的Numpy使用指引(附python演练)
欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/,学习更多的机器学习.深度学习的知识! Numpy 的主要用途是以数组的形式进行数据操作. 机器学习中大多 ...
- spring bean的装载过程简略赏析
spring一个bean的容器,它从这个最基本的功能进而扩展出AOP,transaction,cache,schedule,data等等,将业务与框架代码解耦,让我们可以将大部分精力投入到业务代码中, ...
- Java中的集合类、Lambda、鲁棒性简述
集合类 在java.util包中提供了一些集合类,常用的有List.Set和Map类,其中List类和Set类继承了Collection接口.这些集合类又称为容器,长度是可变的,数组用来存放基本数据类 ...