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中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存 ...
随机推荐
- Vue在点击内部元素时(获得焦点),怎样让外部div元素样式变化?
问题: div内部有很多元素,div. p. span .input等,各元素有嵌套,现在点击某元素时需要最外面这个div边框高亮,例如,点击了input开始输入 假设html 结构如下 <d ...
- Element UI中的上传文件功能
上传文件给后台: <el-upload style="display:inline-block" :limit=" class="upload-demo& ...
- (转)GNU风格ARM汇编语法指南(非常详细)5
原文地址:http://zqwt.012.blog.163.com/blog/static/120446842010111482417545/ 6.GNU汇编程序中的常数 <1> 十 ...
- Linux内核文档:如何写符合 kernel-doc 规范的注释
简介 Linux内核使用 Sphinx 实现把 Documentation 目录下的 reStructuredText 文件转换为非常漂亮的文档.文档既可以通过 make htmldocs 转换成 H ...
- Python3学习之路~9.3 GIL、线程锁之Lock\Rlock\信号量、Event
一 Python GIL(Global Interpreter Lock) 全局解释器锁 如果一个主机是单核,此时同时启动10个线程,由于CPU执行了上下文的切换,让我们宏观上看上去它们是并行的,但实 ...
- 从发布订阅模式入手读懂Node.js的EventEmitter源码
前面一篇文章setTimeout和setImmediate到底谁先执行,本文让你彻底理解Event Loop详细讲解了浏览器和Node.js的异步API及其底层原理Event Loop.本文会讲一下不 ...
- jquery 获取url携带的参数
url= "/page/employee/employeeUpdate.html?id="+data.id 获取 url携带的参数 -> $.getUrlParam = fu ...
- CF1324F Maximum White Subtree 题解
原题链接 简要题意: 给定一棵树,每个点有黑白两种颜色:对每个节点,求出包含当前节点的连通图,使得白点数与黑点数差最小.输出这些值. F题也这么简单,咳咳,要是我也熬夜打上那么一场...可惜没时间打啊 ...
- 升级 nop 4.1 Incorrect syntax near 'OFFSET'. Invalid usage of the option NEXT in the FETCH statement.
Incorrect syntax near 'OFFSET'. Invalid usage of the option NEXT in the FETCH statement. nop.web 项目 ...
- [模板] dfs序
B.树之呼吸-贰之型-dfs序 Time Limit: 1000 MS Memory Limit: 32768 K Total Submit: 42 (16 users) Total Accepted ...