前言

最近我写的几篇线上问题相关的文章:《糟糕,CPU100%了》《如何防止被恶意刷接口》《我调用第三方接口遇到的13大坑》发表之后,在全网广受好评。

今天接着线上问题这个话题,跟大家一起聊聊线上服务出现OOM问题的6种场景,希望对你会有所帮助。

1 堆内存OOM

堆内存OOM是最常见的OOM了。

出现堆内存OOM问题的异常信息如下:

java.lang.OutOfMemoryError: Java heap space

此OOM是由于JVM中heap的最大值,已经不能满足需求了。

举个例子:

public class HeapOOMTest {

    public static void main(String[] args) {
List<HeapOOMTest> list = Lists.newArrayList();
while (true) {
list.add(new HeapOOMTest());
}
}
}

这里创建了一个list集合,在一个死循环中不停往里面添加对象。

执行结果:



出现了java.lang.OutOfMemoryError: Java heap space的堆内存溢出。

很多时候,excel一次导出大量的数据,获取在程序中一次性查询的数据太多,都可能会出现这种OOM问题。

我们在日常工作中一定要避免这种情况。

2 栈内存OOM

有时候,我们的业务系统创建了太多的线程,可能会导致栈内存OOM。

出现堆内存OOM问题的异常信息如下:

java.lang.OutOfMemoryError: unable to create new native thread

给大家举个例子:

public class StackOOMTest {
public static void main(String[] args) {
while (true) {
new Thread().start();
}
}
}

使用一个死循环不停创建线程,导致系统产生了大量的线程。

执行结果:



如果实际工作中,出现这个问题,一般是由于创建的线程太多,或者设置的单个线程占用内存空间太大导致的。

建议在日常工作中,多用线程池,少自己创建线程,防止出现这个OOM。

3 栈内存溢出

我们在业务代码中可能会经常写一些递归调用,如果递归的深度超过了JVM允许的最大深度,可能会出现栈内存溢出问题。

出现栈内存溢出问题的异常信息如下:

java.lang.StackOverflowError

例如:

public class StackFlowTest {
public static void main(String[] args) {
doSamething();
} private static void doSamething() {
doSamething();
}
}

执行结果:

出现了java.lang.StackOverflowError栈溢出的错误。

我们在写递归代码时,一定要考虑递归深度。即使是使用parentId一层层往上找的逻辑,也最好加一个参数控制递归深度。防止因为数据问题导致无限递归的情况,比如:id和parentId的值相等。

4 直接内存OOM

直接内存不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。

它来源于NIO,通过存在堆中的DirectByteBuffer操作Native内存,是属于堆外内存,可以直接向系统申请的内存空间。

出现直接内存OOM问题时异常信息如下:

java.lang.OutOfMemoryError: Direct buffer memory

例如下面这样的:

public class DirectOOMTest {

    private static final int BUFFER = 1024 * 1024 * 20;

    public static void main(String[] args) {
ArrayList<ByteBuffer> list = new ArrayList<>();
int count = 0;
try {
while (true) {
// 使用直接内存
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
list.add(byteBuffer);
count++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
System.out.println(count);
}
}
}

执行结果:

会看到报出来java.lang.OutOfMemoryError: Direct buffer memory直接内存空间不足的异常。

5 GC OOM

GC OOM是由于JVM在GC时,对象过多,导致内存溢出,建议调整GC的策略。

出现GC OOM问题时异常信息如下:

java.lang.OutOfMemoryError: GC overhead limit exceeded

为了方便测试,我先将idea中的最大和最小堆大小都设置成10M:

-Xmx10m -Xms10m

例如下面这个例子:

public class GCOverheadOOM {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < Integer.MAX_VALUE; i++) {
executor.execute(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
});
}
}
}

执行结果:

出现这个问题是由于JVM在GC的时候,对象太多,就会报这个错误。

我们需要改变GC的策略。

在老代80%时就是开始GC,并且将-XX:SurvivorRatio(-XX:SurvivorRatio=8)和-XX:NewRatio(-XX:NewRatio=4)设置的更合理。

最近就业形式比较困难,为了感谢各位小伙伴对苏三一直以来的支持,我特地创建了一些工作内推群, 看看能不能帮助到大家。

你可以在群里发布招聘信息,也可以内推工作,也可以在群里投递简历找工作,也可以在群里交流面试或者工作的话题。

进群方式

添加苏三的私人微信:su_san_java,备注:博客园+所在城市,即可加入。

6 元空间OOM

JDK8之后使用Metaspace来代替永久代,Metaspace是方法区在HotSpot中的实现。

Metaspace不在虚拟机内存中,而是使用本地内存也就是在JDK8中的ClassMetadata,被存储在叫做Metaspace的native memory。

出现元空间OOM问题时异常信息如下:

java.lang.OutOfMemoryError: Metaspace

为了方便测试,我修改一下idea中的JVM参数,增加下面的配置:

-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m

指定了元空间和最大元空间都是10M。

接下来,看看下面这个例子:

public class MetaspaceOOMTest {
static class OOM {
} public static void main(String[] args) {
int i = 0;
try {
while (true) {
i++;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOM.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o, args);
}
});
enhancer.create();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}

执行结果:



程序最后会报java.lang.OutOfMemoryError: Metaspace的元空间OOM。

这个问题一般是由于加载到内存中的类太多,或者类的体积太大导致的。

好了,今天的内容先分享到这里,下一篇文章重点给大家讲讲,如何用工具定位OOM问题,敬请期待。

最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描下发二维码关注一下,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

关注公众号:【苏三说技术】,在公众号中回复:面试、代码神器、开发手册、时间管理有超赞的粉丝福利,另外回复:加群,可以跟很多BAT大厂的前辈交流和学习。

工作中最常见的6种OOM问题的更多相关文章

  1. 数据科学中的常见的6种概率分布(Python实现)

    作者:Pier Paolo Ippolito@南安普敦大学 编译:机器学习算法与Python实战(微信公众号:tjxj666) 原文:https://towardsdatascience.com/pr ...

  2. 十七、Java中数组常见的几种排序方法!

    转载自:https://www.cnblogs.com/bekeyuan123/p/6891875.html 数组的定义: // 3种定义方式 int[] arr = new int[5]; int[ ...

  3. 汇编中PTR常见的几种用法

    汇编中PTR的用法确实是令人比较头疼的,我特意搜集了一些PTR的应用实例,可以从例子中揣摩出规律: 1.MOV    WORD PTR [DI],OFFSET BUF1 2.SUB    BYTE   ...

  4. java中最常见的几种运行时异常,你get了吗?

    NullPointerException (空指针异常) ClassCastException (类型强制转换异常) NumberFormatException (数字格式异常) NegativeAr ...

  5. KETTLE4个工作中有用的复杂实例--1、数据定时自动(自动抽取)同步作业

    今天呕心沥血花了8个小时给大家带来kettle工作中最常见的四种复杂实例,90%的项目用到这4种实例都可以解决. 4种实例种还有2种通用kettle工具,使用这两种通用工具实例,可以直接修改相应的配置 ...

  6. css布局 - 工作中常见的两栏布局案例及分析

    突然想到要整理这么一篇平时工作中相当常见但是我们又很忽视的布局的多种处理方法.临时就在我经常浏览的网站上抓的相对应的截图.(以后看到其他类型的我再补充) 既然截了图,咱们就直接看人家使用的布局方式,毕 ...

  7. [工作中的设计模式]享元模式模式FlyWeight

    一.模式解析 Flyweight在拳击比赛中指最轻量级,即“蝇量级”或“雨量级”,这里选择使用“享元模式”的意译,是因为这样更能反映模式的用意.享元模式是对象的结构模式.享元模式以共享的方式高效地支持 ...

  8. 简洁优雅的Python教你如何在工作中“偷懒”

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: A字头 PS:如有需要Python学习资料的小伙伴可以加点击下方链 ...

  9. 教你如何在工作中“偷懒”,python优雅的帮你解决

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取htt ...

  10. 工作中常见的五种技术leader

    力不从心型 在工作中有种技术leader,总认为自己是最好的.在方案设计的时候,自己有一种方案,下属有一种方案.leader非要别人听他的.如果两种方案没有优劣之分,比较建议的做法是让真正实施的人按照 ...

随机推荐

  1. Delphi 官方 MD5

    去官方文档搜就行了,引入System.Hash 单元: http://docwiki.embarcadero.com/Libraries/Athens/en/System.Hash.THashMD5 ...

  2. Linux--Vi编辑命令(跳到指定行、翻屏、缩进)

    1.设置行号 如果编辑后,又想显示行号,同样操作按一下esc键,并输入:(冒号),输入set number    ,并按回车键,完成后即显示行号. 不需要显示行号,同样操作按一下esc键,并输入:(冒 ...

  3. 探索C语言中的联合体与枚举:数据多面手的完美组合!

    ​ 欢迎大家来到贝蒂大讲堂 养成好习惯,先赞后看哦~ 所属专栏:C语言学习 贝蒂的主页:Betty's blog 1. 联合体的定义 联合体又叫共用体,它是一种特殊的数据类型,允许您在相同的内存位置存 ...

  4. 【JS】一个思路搞定三道Promise并发编程题,手摸手教你实现一个Promise限制器

    壹 ❀ 引 之前在整理手写Promise相关资料时,在文章推荐区碰巧看到了一道手写Promise并发控制调度器的笔试题(大厂可能爱考),结果今天同事又正好问了我一个关于Promise调度处理的场景问题 ...

  5. NC15291 幸运数字Ⅱ

    题目链接 题目 题目描述 定义一个数字为幸运数字当且仅当它的所有数位都是4或者7. 比如说,47.744.4都是幸运数字而5.17.467都不是. 定义next(x)为大于等于x的第一个幸运数字.给定 ...

  6. Python 中global 关键字理解

    Python中的global关键字,你了解吗? 前言 今天来了解下 Python 中的 global 关键字. Python变量的作用域 实战案例演示之前,先要了解下 Python 的作用域. Pyt ...

  7. 【framework】WMS启动流程

    1 前言 ​ WMS 是 WindowManagerService 的简称. (1)WMS 主要职责 窗口管理:负责启动.添加.删除窗口,管理窗口大小.层级,核心成员有:WindowContainer ...

  8. 微信小程序获取本日、本周、本月、本年时间段

    原文链接 https://cslaoxu.vip/110.html 说明 最近需要用到统计不同时间段内的记录数,所以找了一下现成的工具类.下面就演示一下如何引用到实际项目中. 详细用法请参考:http ...

  9. Android里使用AspectJ实现双击自定义注解

    创建注解 首先创建一个双击注解. import java.lang.annotation.ElementType; import java.lang.annotation.Retention; imp ...

  10. C++ 多线程的错误和如何避免(6)

    加锁的临界区要尽可能的紧凑和小型 问题分析: 当一个线程在临界区内执行时,所有其他试图进入临界区的线程都会被阻止,所以我们应该保证临界区尽可能的小.比如, void CallHome(string m ...