嗯,生活加油鸭。。。。 实习中遇到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错误解析(面试可以聊的东西)的更多相关文章

  1. 转:在java中使用dom4j解析xml

    JAVA 使用Dom4j 解析XML Java DOM4J Parser - Parse XML Document Dom4j下载及使用Dom4j读写XML简介 在java中使用dom4j解析xml ...

  2. JAVA中生成、解析二维码图片的方法

    JAVA中生成.解析二维码的方法并不复杂,使用google的zxing包就可以实现.下面的方法包含了生成二维码.在中间附加logo.添加文字功能,并有解析二维码的方法. 一.下载zxing的架包,并导 ...

  3. 沉淀再出发:java中线程池解析

    沉淀再出发:java中线程池解析 一.前言 在多线程执行的环境之中,如果线程执行的时间短但是启动的线程又非常多,线程运转的时间基本上浪费在了创建和销毁上面,因此有没有一种方式能够让一个线程执行完自己的 ...

  4. java中static关键字解析

    static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键字的用法和平常容易误解的地方,最后列 ...

  5. Java中的Html解析:使用jsoup

    包:jsoup-1.10.2.jar import java.io.File; import java.io.IOException; import org.jsoup.Jsoup; import o ...

  6. java中采用dom4j解析xml文件

    一.前言 在最近的开发中用到了dom4j来解析xml文件,以前听说过来解析xml文件的几种标准方式:但是从来的没有应用过来,所以可以在google中搜索dmo4j解析xml文件的方式,学习一下dom4 ...

  7. java中main函数解析(转载)

    从写java至今,写的最多的可能就是主函数 public static void main(String[] args) {} 但是以前一直都没有问自己,为什么要这么写,因为在c语言中就没有这样子的要 ...

  8. Java中的框架基础面试知识

    spring mvc 工作机制(原理): DispatcherServlet主要用作职责调度工作,本身主要用于控制流程 Spring mvc运行原理 1.springmvc将所有的请求都提交给Disp ...

  9. Java中volatile关键字解析

    一.内存模型的相关概念 大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存 ...

随机推荐

  1. HTML5&CCS3(1) 网页的构造块

    HTML用于定义内容的含义,而CSS(Cascading Style Sheet,层叠样式表)用于定义内容和网页如何显示.HTML页面和CSS文件(样式表,stylesheet)都是文本文件,因此很容 ...

  2. 强连通分量SCC 2-SAT

    强连通分量SCC 2-SAT 部分资料来自: 1.https://blog.csdn.net/whereisherofrom/article/details/79417926 2.https://ba ...

  3. spring的ioc依赖注入的三种方法(xml方式)

    常见的依赖注入方法有三种:构造函数注入.set方法注入.使用P名称空间注入数据.另外说明下注入集合属性 先来说下最常用的那个注入方法吧. 一.set方法注入 顾名思义,就是在类中提供需要注入成员的 s ...

  4. Burpsuite被动扫描流量转发插件:Passive Scan Client

    编译成品:链接: https://pan.baidu.com/s/1E0vsPGgPgB9bXCW-8Yl1gw 提取码: 49eq Passive Scan Client Burpsuite被动扫描 ...

  5. thinkphp5.0.*命令执行批量脚本

    import requests import Queue import threading import time user_agent = "Mozilla/5.0 (Windows NT ...

  6. [gcd,灵感] Codeforces 1200C Round Corridor

    题目:https://codeforces.com/contest/1200/problem/C C. Round Corridor time limit per test 1 second memo ...

  7. Java基础语法(6)-注释

    title: Java基础语法(6)-注释 blog: CSDN data: Java学习路线及视频 用于注解说明解释程序的文字就是注释. 提高了代码的阅读性:调试程序的重要方法. 注释是一个程序员必 ...

  8. 一文综述python读写csv xml json文件各种骚操作

      Python优越的灵活性和易用性使其成为最受欢迎的编程语言之一,尤其是对数据科学家而言.这在很大程度上是因为使用Python处理大型数据集是很简单的一件事情. 如今,每家科技公司都在制定数据战略. ...

  9. 最新SCI影响因子发布!Nature屠榜,AI领域Top 1000期刊盘点

    [导读]2018年度SCI期刊影响因子最新发布,Nature.Science.Cell三大神刊排名前列.新智元摘取其中有关人工智能.机器学习.计算机视觉.机器人学等领域的期刊并做简要介绍,希望对读者选 ...

  10. 2.Grpc消息定义

    一个简单示例 syntax ="proto3";//设置默认版本,不写默认为proto2 //1,2,3 是字段的标记 Tag 不表示字段的值 message FirstMessa ...