内存溢出(OOM)分析
- Java heap space:堆空间不足
- GC overhead limit exceeded : GC开销超出限制
- Permgen space:永久代内存不足
- Metaspace:元空间内存不足
- Unable to create new native thread:无法创建新的本地线程
- Out of swap space? : 交换空间内存不足
- Kill process or sacrifice child
Java heap space:堆空间不足
- 通用解决方案:通过-Xmx设置更大的堆内存【该方式可能只是延迟报错的发生,如果不能从根本上找到原因,报错还是可能会发生】
- 进一步原因分析及解决方案:
- 流量/数据量峰值 : 可以考虑添加机器资源,或者做限流
- 内存泄漏 : 需要找到持有的对象,修改代码
- 创建了一个超大对象(通常是一个大数组) : 可以进行业务切分
- 代码示例
- 内存泄漏【-Xmx10m】
package oom; import java.util.HashMap;
import java.util.Map; /**
* 内存泄露
*/
public class JavaHeapSpace2 { public static void main(String[] args) {
Map<Key,String> map = new HashMap<>();
while (true) {
Key key = new Key();
if(!map.containsKey(key)) {
map.put(key, "Java Overhead");
System.out.println(key);
}
} }
} class Key { }
oom.Key@2ef70cb4
......
oom.Key@457298d0
oom.Key@484b94f2
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.HashMap.resize(HashMap.java:704)
at java.util.HashMap.putVal(HashMap.java:663)
at java.util.HashMap.put(HashMap.java:612)
at oom.JavaHeapSpace2.main(JavaHeapSpace2.java:16)
View Result
- 创建了一个超大对象
package oom; import java.lang.management.ManagementFactory;
import java.util.List; public class JavaHeapSpace { private static final int SIZE = 12 * 1024 * 2014; public static void main(String[] args) {
List<String> inputArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
System.out.println("JVM Arguments : " + inputArguments);
int[] arr = new int[SIZE];
}
}
JVM Arguments : [-Xmx12m, -Dfile.encoding=GBK]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at oom.JavaHeapSpace.main(JavaHeapSpace.java:13) Process finished with exit code 1
View Result[-Xmx12m]
JVM Arguments : [-Xmx35m,-Dfile.encoding=GBK] Process finished with exit code 0
View Result[-Xmx35m]
GC overhead limit exceeded : GC开销超出限制
- 代码演示【使用默认的VM配置】
package oom; import java.util.HashMap;
import java.util.Map; public class JavaHeapSpace2 { public static void main(String[] args) {
Map<Key,String> map = new HashMap<>();
while (true) {
Key key = new Key();
if(!map.containsKey(key)) {
map.put(key, "Java Overhead");
System.out.println(key);
}
}
}
} class Key { }
oom.Key@61f7f66c
oom.Key@1da844d
......
oom.Key@792b37e7
oom.Key@3d8151c0Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.nio.CharBuffer.wrap(CharBuffer.java:373)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
View Result
- 背景:永久代主要存储类的信息,比如:类加载引用、运行时常量池、字段、方法等。因此,Permgen的大小取决于被加载类的数量及类的大小。
- 原因:
- 加载了太多的类
- 加载了超大类
- 注意:JDK8已经完全移除永久代空间,取而代之的是元空间(Metaspace)
- 背景:Metaspace存储类的元数据信息
- 原因:
- 加载了太多的类
- 加载了超大类
- 解决方案
- 调整-XX:MaxMetaspaceSize参数
- 删除-XX:MaxMetaspaceSize参数,解除限制【默认是没有限制的。默认情况下,对于64位服务器端JVM,MetaspaceSize默认大小是21M(初始限制值),一旦达到这个限制值,FullGC将被触发进行类卸载,并且这个限制值将会被重置,新的限制值依赖于Metaspace的剩余容量。如果没有足够空间被释放,这个限制值将会上升。】
- 代码演示【JDK1.8】
package oom; import javassist.CannotCompileException;
import javassist.ClassPool; import java.lang.management.ManagementFactory;
import java.util.List; public class Metaspace{ public static void main(String[] args) throws CannotCompileException {
List<String> inputArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
System.out.println("JVM Arguments : " + inputArguments); for (int i = 0; i < 100000000; i++) {
ClassPool.getDefault().makeClass("User" + i).toClass();
}
}
}
JVM Arguments : [-XX:MaxMetaspaceSize=35m, -Dfile.encoding=GBK]
Exception in thread "main" javassist.CannotCompileException: by java.lang.OutOfMemoryError: Metaspace
at javassist.ClassPool.toClass(ClassPool.java:1099)
at javassist.ClassPool.toClass(ClassPool.java:1042)
at javassist.ClassPool.toClass(ClassPool.java:1000)
at javassist.CtClass.toClass(CtClass.java:1224)
at oom.Permgen.main(Permgen.java:16)
Caused by: java.lang.OutOfMemoryError: Metaspace
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at javassist.ClassPool.toClass2(ClassPool.java:1112)
at javassist.ClassPool.toClass(ClassPool.java:1093)
... 4 more
View Result
- 背景:每个线程都需要一定的内存空间,当JVM向底层操作系统请求创建一个新的native线程时,如果没有足够的资源分配就会报这个错误
- 原因分析及解决方案:
- 线程数超过了OS最大线程数ulimit限制 : 调高 OS 层面的线程最大数 - 执行 ulimia-a 查看最大线程数限制,使用 ulimit-u xxx 调整最大线程数限制
- 线程数超过了本地线程最大数:限制线程池大小 ;
- native内存不足 :
- 使用 -Xss 参数减少线程栈的大小
- 升级配置,为机器提供更多的内存
- 代码示例
package oom; public class UnableCreateThread { public static void main(String[] args) {
while (true) {
new Thread(() -> {
try {
Thread.sleep(100000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006a674447, pid=18648, tid=0x0000000000067b68
#
# JRE version: Java(TM) SE Runtime Environment (8.0_171-b11) (build 1.8.0_171-b11)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.171-b11 mixed mode windows-amd64 compressed oops)
# Problematic frame:
# V [jvm.dll+0x214447][thread 424944 also had an error]
An unrecoverable stack overflow has occurred.
[thread 424964 also had an error]
An unrecoverable stack overflow has occurred.
[thread 424984 also had an error]
[thread 424992 also had an error]
An unrecoverable stack overflow has occurred.
[thread 424988 also had an error]
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
at java.lang.Thread.start0(Native Method)
at java.lang.Thread.start(Thread.java:717)
at oom.UnableCreateThread.main(UnableCreateThread.java:14)
View Result
- 背景:虚拟内存(Virtual Memory)由物理内存(Physical Memory)和交换空间(Swap Space)两部分组成。在JVM请求的总内存大于可用物理内存的情况下,操作系统会将内存中的数据交换到磁盘上去。当交换空间也将耗尽时就会报 Outof swap space? 错误。
- 原因分析及解决方案:【往往是由操作系统级别的问题引起的】
- 操作系统配置的交换空间不足 :
- 加交换空间【对交换空间运行垃圾回收算法会使GC暂停的时间增加几个数量级,因此使用增加交换空间的方法】
- 升级机器以包含更多内存
- 系统上的另一个进程消耗所有内存资源:如果应用部署在JVM需要同其他进程激烈竞争获取资源的物理机上,建议将服务隔离到单独的虚拟机中
- 本地内存泄漏导致应用程序失败: 优化应用程序以减少其内存占用
- 背景:操作系统是建立在进程的概念之上,这些进程在内核中作业,其中有一个非常特殊的进程,名叫“内存杀手(Out of memory killer)”。当内核检测到系统内存不足时,OOM killer被激活,然后选择一个进程杀掉。
- 原因分析:程序占用大量系统内存导致其他进程没有可用内存
- 解决方案:
- 调整OOM Killer配置
- 升级机器以包含更多内存
内存溢出(OOM)分析的更多相关文章
- JVM:内存溢出OOM
JVM:内存溢出OOM 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 经典错误 JVM 中常见的两个 OOM 错误 StackoverflowError:栈溢出 ...
- 内存溢出(Oom)和内存泄露(Memory leak)
1.概念 内存溢出(Oom):1.内存不够用:2.数据长度短的数据类型存储了一个数据长度较大的数据类型:3.一个结果 内存泄露(Memory leak):1.忘记释放已用内存,内存管理较为常见的现象: ...
- 内存溢出OOM与内存泄漏ML
附, 微信团队原创分享:Android内存泄漏监控和优化技巧总结 一.如何避免OOM 异常 想要避免OOM 异常首先我们要知道什么情况下会导致OOM 异常. 1.图片过大导致OOM Android 中 ...
- java常见内存溢出(OOM)
jvm内存区域 程序计数器一块很小的内存空间,作用是当前线程所执行的字节码的行号指示器. java栈与程序计数器一样,java栈(虚拟机栈)也是线程私有的,其生命周期与线程相同.通常存放基本数据类型, ...
- Java常见内存溢出异常分析(OutOfMemoryError)
原文转载自:http://my.oschina.net/sunchp/blog/369412 1.背景知识 1).JVM体系结构 2).JVM运行时数据区 JVM内存结构的相关可以参考: http:/ ...
- JVM:Java常见内存溢出异常分析
转载自:http://www.importnew.com/14604.html Java虚拟机规范规定JVM的内存分为了好几块,比如堆,栈,程序计数器,方法区等,而Hotspot jvm的实现中,将堆 ...
- 本地模拟内存溢出并分析Dump文件
java Dump文件分析 前言 dump文件是java虚拟机内存在某一时间点的快照文件,一般是.hprof文件,下面自己模拟一下本地内存溢出,生成dump文件,然后通过mat工具分析的过程. 配置虚 ...
- android 内存溢出问题分析
最近的项目中,内存一直再增长,但是不知道是什么问题,导致内存溢出,在网上看到了这么一篇关于内存分析与管理的文章,解决了部分问题,感觉这篇文 章还不错,就转帖到我的blog上了,希望对大家有所帮助. ...
- bitmap 内存溢出OOM的解决办法分享
昨天遇到这个问题就是从一个输入流里调用BitmapFactory.decodeStream(this.getContentResolver().openInputStream(uri))得到一个bit ...
随机推荐
- sqlserver 把c#代码的string[] 的ids转换成一个数据table表
declare @string varchar(200),@sql varchar(1000)set @string = '1,2,3,4,5,6'set @sql = 'select code='' ...
- 记一次 .NET 差旅管理后台 CPU 爆高分析
一:背景 1. 讲故事 前段时间有位朋友在微信上找到我,说他的 web 系统 cpu 运行一段时候后就爆高了,让我帮忙看一下是怎么回事,那就看吧,声明一下,我看 dump 是免费的,主要是锤炼自己技术 ...
- DNS 系列(三):如何免受 DNS 欺骗的侵害
互联网上每一台设备都会有一个 IP 地址,我们在访问网站或发送信息时,其实都是通过 IP 地址达成准确请求的.但是这个 IP 地址由很长一串数字组成,记忆起来相当困难,所以我们创造了更实用的域名来代替 ...
- shell查询prometheus数据
#shell查询prometheus数据 shell使用curl调用HTTP API执行PromQL /api/v1/query查询某一时刻的数据 查询条件PromSQL复杂时, 传入接口/api/v ...
- day01--DOS常用命令
打开CMD的方式 开始+系统+命令提示符 Win键+R输入cmd打开控制台(推荐使用) 在任意的文件夹下面,按住shift键+鼠标右键点击,在此处打开命令行窗口 资源管理器的地址栏前面加,上cmd路径 ...
- 前端(五)-Vue简单基础
1. Vue概述 Vue (读音/vju/, 类似于view)是一套用于构建用户界面的渐进式框架,发布于2014年2月. 与其它大型框架不同的是,Vue被设计为可以自底向上逐层应用. Vue的核心库只 ...
- [RCTF2015]EasySQL-1|SQL注入
1.打开之后只有登录和注册两个功能,界面如下: 2.随便注册一个账户并进行登录,(注册admin时显示该账户已存在,考虑到是不是要获取到admin账户),发现可以进行改密操作,结果如下: 3.抓取各个 ...
- 汽车锂电池行业为啥会选择钡铼BL200系列Profinet分布式IO
近年来,全球新能源汽车的蓬勃发展促进了锂电池行业的发展.随着锂电池标准化程度的提高,电池和模块规格的标准化是未来的发展趋势,也促进了自动化模块生产线的发展. 锂电池模块生产线通过涂胶-电池堆叠-组装- ...
- vue之请求axios
如有不正,请指正! 一.为什么选择axios1.ajax 混乱复杂难用2.vue-resource 官方不在维护 ajax的封装3.所以所以 axios 对promise的封装 promise 更优雅 ...
- java日常开发必备:list的四种遍历
在平时的开发过程中使用List的场景很多,你知道List的遍历有多少种方式?今天一起来梳理下List的几种遍历方式.这里以java.util.ArrayList为例来演示. 这里有一个最简单的 ...