论JVM爆炸的几种姿势及自救方法
前言
如今不管是在面试还是在我们的工作中,OOM总是不断的出现在我们的视野中,所以我们有必要去了解一下导致OOM的原因以及一些基本的调整方法,大家可以通过下面的事例来了解一下什么样的代码会导致OOM,帮助我们以后在工作中能够通过异常信息来判断是JVM里面哪个区域出现了问题。
先介绍一下笔者的相关编码环境。
jdk:java version "1.8.0_121"
ide:IntelliJ IDEA 2019.1 (Community Edition)
正文
1、Java堆溢出
Java中的堆存储的都是对象实例,当我们不断的创建对象,而GC的时候又不能回收,当存储的对象大小超过了-Xmx的值,这时候则会出现OutOfMemoryError.[-XX:+HeapDumpOnOutOfMemoryError]参数可以让jvm出现内存溢出的时候dump出内存堆转储快照。
/**
* VM Args: -Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
* @author wangzenghuang
*/
public class HeapOOMDemo {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
while(true){
stringList.add("str");
}
}
}
运行结果,发生OOM,并且在我们项目的根目录dump出当前的内存堆快照
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid1376.hprof ...
Heap dump file created [7972183 bytes in 0.047 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:261)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
at java.util.ArrayList.add(ArrayList.java:458)
at HeapOOMDemo.main(HeapOOMDemo.java:12) Process finished with exit code 1
简单解决思路
那么发生这个问题以后我们的解决思路有哪些呢?我们可以利用一些工具(例如Eclipse Memory Analyzer )来分析dump出的文件,一般来说,当生产环境发生OOM,比较常见的一个原因是发生了内存泄漏,用工具可以分析出泄露的对象到GC Root的引用链,从而定位到问题代码。假如经过分析后发现内存中的对象都是“必须存活”的对象,这时候就要思考下项目中是否把“-Xms跟-Xmx”设置得太小了(当然这里也不是随意调大,需要结合机器的物理内存情况),再者需要留意代码中是否有一些长生命周期的对象,从代码中优化内存消耗。
2、方法区溢出
在jvm的方法区中,它主要存放了类的信息,常量,静态变量等。在jdk8以前是通过“-XX:PermSize,-XX:MaxPermSize”来调整这个区域的值,但是从8开始呢,永久代的概念被MetaSpace(元空间)代替了,对应的参数也变成了“-XX:MetaspaceSize,-XX:MaxMetaspaceSize”。在这个例子中使用CGLib来动态生成一些类,方便我们实验操作。
/**
* VM Args: -XX:MetaspaceSize=5m -XX:MaxMetaspaceSize=5m
* @author wangzenghuang
*/
public class MethodAreaOOMDemo {
public static void main(String[] args) {
while(true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(obj,objects);
}
});
enhancer.create();
}
}
static class OOMObject{}
}
运行结果
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
简单解决方法
这个问题的话,一般来说根据情况调整方法区的大小就行了,网上也有人说可以去掉MetaSpace的的大小限制,但是不建议这么干,毕竟不可控的事情我们要少点干,很容易给自己埋雷。
3.栈溢出
对于我们来说,还有一个熟悉的错误,那就是“StackOverflowError”,它是由线程请求的栈深度超过了jvm允许的最大范围而产生的。“-Xss”参数可以设置栈容量。
/**
* VM Args: -Xss128k
* @author wangzenghuang
*/
public class StackOFDemo {
private static int stackLength = 1; public void stackLeak(){
stackLength++;
stackLeak();
} public static void main(String[] args) {
StackOFDemo stackOFDemo = new StackOFDemo();
try {
stackOFDemo.stackLeak();
}catch (Throwable e){
System.out.println("length : "+ stackLength);
throw e;
}
}
}
运行结果
length : 983
Exception in thread "main" java.lang.StackOverflowError
at StackOFDemo.stackLeak(StackOFDemo.java:10)
at StackOFDemo.stackLeak(StackOFDemo.java:10)
...
简单解决思路
一般来说此类问题多出现在存在递归的地方,要从代码里重新审视递归未结束的原因,若递归的方法没问题可以根据实际情况调整“-Xss”参数的大小。还有一些代码的循坏依赖也会造成此类情况,
4.直接内存溢出
本机直接内存默认与“-Xmx”设定的值一样大,可以通过“-XX:MaxDirectMemorySize”修改。
/**
* VM Args: -Xmx20m -XX:MaxDirectMemorySize=10
* @author wangzenghuang
*/
public class DirectMemoryOOMDemo {
private static final int _1MB = 1024 * 1024; public static void main(String[] args) throws IllegalAccessException {
Field field = Unsafe.class.getDeclaredFields()[0];
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
while (true){
unsafe.allocateMemory(_1MB);
}
}
}
运行结果
呃,一运行这段代码idea直接闪退了,查阅其他资料可以得知当DirectMemory导致内存溢出时,Heap Dump文件是很小的,如果程序中有使用NIO的情况可以检查一下。
总结
这里所展示的代码只是可以触发jvm的各种错误,但是并不代表这是唯一的触发错误的方方式,假如我们的代码比较复杂,有时候遇到类似错误的时候还是需要耐心分析。
该文章首发于微信公众号《深夜里的程序猿》,转载请注明出处,侵权必究。
论JVM爆炸的几种姿势及自救方法的更多相关文章
- 论JVM爆炸的几种姿势及自救方法,你不得不知!
前言 如今不管是在面试还是在我们的工作中,OOM总是不断的出现在我们的视野中,所以我们有必要去了解一下导致OOM的原因以及一些基本的调整方法,大家可以通过下面的事例来了解一下什么样的代码会导致OOM, ...
- 【bzoj3224】Tyvj 1728 普通平衡树 01Trie姿势+平衡树的四种姿势 :splay,旋转Treap,非旋转Treap,替罪羊树
直接上代码 正所谓 人傻自带大常数 平衡树的几种姿势: AVL Red&Black_Tree 码量爆炸,不常用:SBT 出于各种原因,不常用. 常用: Treap 旋转 基于旋转操作和随机数 ...
- 快速了解IOC的几种姿势
一.首先我们了解IOC如何注入的几种姿势 构造函数注入(Constructor Injection) Ioc容器会智能的选择和调用合适的构造函数以创建依赖的对象.如果被选择的构造函数具有相应的参数,I ...
- 两个文件去重的N种姿势
最近利用shell帮公司优化挖掘关键词的流程,用shell替代了多个环节的操作,极大提高了工作效率. shell在文本处理上确有极大优势,比如多文本合并.去重等,但是最近遇到了一个难搞的问题,即两个大 ...
- 又拍云张聪:OpenResty 动态流控的几种姿势
2019 年 1 月 12 日,由又拍云.OpenResty 中国社区主办的 OpenResty × Open Talk 全国巡回沙龙·深圳站圆满结束,又拍云首席架构师张聪在活动上做了< Ope ...
- 补习系列(7)-springboot 实现拦截的五种姿势
目录 简介 姿势一.使用 Filter 接口 1. 注册 FilterRegistrationBean 2. @WebFilter 注解 姿势二.HanlderInterceptor 姿势三.@Exc ...
- python打开文件的N种姿势
# python打开文件的N种姿势 print('[1]使用open()函数+简单for循环') f1 = open('python.txt') for line in f1: print(line. ...
- [转]地图投影的N种姿势
此处直接给出原文链接: 1.地图投影的N种姿势 2.GIS理论(墨卡托投影.地理坐标系.地面分辨率.地图比例尺.Bing Maps Tile System)
- SpringBoot系列教程web篇Servlet 注册的四种姿势
原文: 191122-SpringBoot系列教程web篇Servlet 注册的四种姿势 前面介绍了 java web 三要素中 filter 的使用指南与常见的易错事项,接下来我们来看一下 Serv ...
随机推荐
- 分布式逻辑管理平台XXL-GLUE
<分布式逻辑管理平台XXL-GLUE> 一.简介 1.1 概述 XXL-GLUE 是一个分布式环境下的 "可执行逻辑单元" 管理平台, 学习简单,扩展JVM的动态 ...
- (四)SpringBoot2.0基础篇- 多数据源,JdbcTemplate和JpaRepository
在日常开发中,经常会遇到多个数据源的问题,而SpringBoot也有相关API:Configure Two DataSources:https://docs.spring.io/spring-boot ...
- asp.net 六大对象之Request、Response
ASP.NET的六大对象,本质上只是 Context 里面的属性,严格上不是对象. 1.Request-->读取客户端在Web请求期间发送的值 2.Response-->封装了页面执行期后 ...
- windows开发的python移植到linux的问题
2016年1月28日 这个问题已经自己解决 file-setting下 左侧code style line separator下拉选择unix就可以了 我在windows上开发的python想移 ...
- table中的一些另类标签
thead/tbody/tfoot/caption/colgroup 注意:thead/tbody/tfoot三部分内容不受编辑顺序影响只和标签本身含义从头到脚显示不能把两个tbody的内容进行合并单 ...
- django+appium实现UI自动化测试平台---构思版
背景 UI自动化,在进行的过程中,难免会遇到平台化, 在实际的工作中,有的领导也会想要实现自动化测试的平台化.自动化平台化后,有了更为实际的成果, 在做UI自动化,很想吧现在的自动化 ...
- Python微信公众号开发
最近老大叫我学习开发微信,试着玩了下.网上查了下文档.有点过时. 简单步骤: 1)申请服务器并完成环境配置 去腾讯云购买云服务器.当然你也可以购买其他产品,比如阿里云.因为我是学生,有优惠110一年. ...
- Hadoop平台基本组成
1.Hadoop系统运行于一个由普通商用服务器组成的计算集群上,能提供大规模分布式数据存储资源的同时,也提供了大规模的并行化计算资源. 2.Hadoop生态系统 3.MapReduce并行计算框架 M ...
- MySql 物理文件组成
1.日志文件 MySQL 各类日志文件介绍 2.数据文件 MySQL 各类数据文件介绍
- YII框架CGridView sql有条件分页实现
$SQL="SELECT * FROM {{user}} WHERE `typeff`=2 order by create_time desc"; $SQL_count=" ...