本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:codedq,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
最近有人在微信群里问我,定时器 OOM(java.lang.OutOfMemoryError: Java heap space)了,其他功能还正常吗?
说实话我之前在浦发的时候,也有遇到过。一个同事写了一个定时备份数据的功能,有一次做活动导致数据量增了好几倍,备份的时候定时任务发生了 OOM,导致数据没有备份成功。这个问题直到第二天才被发现,因为 OOM 后,其他功能都正常,业务都没发现。
第二天是怎么发现的呢?因为第二天业务发现定时发短信的定时任务不执行了,于是大家一顿排查发现系统在昨天就已经 OOM 了。现在影响扩大了,导致其他功能不可用,进而蔓延到整个系统。
在这个过程中,我们先不说这个备份合不合理,我们从 JVM 内存结构来说说为什么一个线程 OOM 了,其他线程不受影响。
这个不受影响,大家别误会。一个线程 OOM 后,其他线程是可以正常运行的,但是内存泄露之后进而会导致整个程序内存溢出,最终程序不可用。
那么我们下面说一下,一个线程 OOM 了,为什么其他线程不受影响呢?
要回答这个问题,我们先来回想一下 java 的内存结构。如下图所示:
我们知道,多线程的时候,每个线程都拥有一个栈和一个程序计数器。栈和程序计数器用来保存线程的执行历史和线程的执行状态,是线程私有的资源。堆是线程共享的,所以理论上一个线程 OOM 了,其他线程应该受影响才对啊,实际上却并不是,这是什么原因呢?
有兴趣的可以按照我下面的这段代码自己去跑一下,测试一下这个内存溢出。
public class HeapOutOfMemoryError { //业余草:www.xttblog.com public static class OOMObject {} public static void main(String[] args) { new Thread(() -> { while(true){ System.out.println(new Date().toString() + Thread.currentThread() + "www.xttblog.com"); try { Thread.sleep(1000); } catch (Exception e) { e.printStackTrace(); } } }).start(); new Thread(() -> { List<Object> list=new ArrayList<>(); // 不断创建对象,并保证GC Roots到对象之间有可达路径,避免垃圾回收清除创建的对象 while (true) { list.add(new OOMObject()); System.out.println(System.currentTimeMillis()); } }).start(); } }
再测试的时候,可以将内存设置的很小,便于重现。
-Xms1m -Xmx2m
-Xms 初始堆内存
-Xmx 最大堆内存
然后结合 JvisualVM 工具,你会看到,在程序内存溢出之后,溢出的内存的线程所占的内存会被快速释放。如下图所示:
不会 JvisualVM 的,可以查看我的这篇文章:使用VisualVM对JAVA程序进行性能分析及调优。
根据上图,我们可以得出当一个线程抛出 OOM 异常后,它所占据的内存资源会被快速的释放掉,从而不会影响其他线程的运行!
另外当一个线程 OutOfMemoryError 后,如果这个 OutOfMemoryError 被捕获,那么 catch 之后吞掉的话程序还能试着继续运行。发生 OutOfMemoryError 之后,只是当前这个线程申请更多的内存的时候不被 JVM 允许,所以会抛出 OutOfMemoryError 异常。当抛出 OutOfMemoryError 异常后,当前这个线程会被退出,它所占的内存会被 JVM 清理掉。
那么 JVM 为什么要这么设计呢?
答案是,Java 程序通常不是为了适应意外的异常而设计的,OOM 之后可能导致应用状态不一致,建议最好重启。
参考资料
最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号1:xmtxtt(5000人已满),微信号2:xttblog(5000人已满),微信号3:codedq(超3800)。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!
本文原文出处:业余草: » 定时器 OOM(OutOfMemoryError) 了,其他线程受影响吗?