定时器 OOM(OutOfMemoryError) 了,其他线程受影响吗?

最近有人在微信群里问我,定时器 OOM(java.lang.OutOfMemoryError: Java heap space)了,其他功能还正常吗?

说实话我之前在浦发的时候,也有遇到过。一个同事写了一个定时备份数据的功能,有一次做活动导致数据量增了好几倍,备份的时候定时任务发生了 OOM,导致数据没有备份成功。这个问题直到第二天才被发现,因为 OOM 后,其他功能都正常,业务都没发现。

第二天是怎么发现的呢?因为第二天业务发现定时发短信的定时任务不执行了,于是大家一顿排查发现系统在昨天就已经 OOM 了。现在影响扩大了,导致其他功能不可用,进而蔓延到整个系统。

在这个过程中,我们先不说这个备份合不合理,我们从 JVM 内存结构来说说为什么一个线程 OOM 了,其他线程不受影响。

这个不受影响,大家别误会。一个线程 OOM 后,其他线程是可以正常运行的,但是内存泄露之后进而会导致整个程序内存溢出,最终程序不可用。

那么我们下面说一下,一个线程 OOM 了,为什么其他线程不受影响呢?

要回答这个问题,我们先来回想一下 java 的内存结构。如下图所示:

JVM 内存结构

我们知道,多线程的时候,每个线程都拥有一个栈和一个程序计数器。栈和程序计数器用来保存线程的执行历史和线程的执行状态,是线程私有的资源。堆是线程共享的,所以理论上一个线程 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

不会 JvisualVM 的,可以查看我的这篇文章:使用VisualVM对JAVA程序进行性能分析及调优。

根据上图,我们可以得出当一个线程抛出 OOM 异常后,它所占据的内存资源会被快速的释放掉,从而不会影响其他线程的运行!

另外当一个线程 OutOfMemoryError 后,如果这个 OutOfMemoryError 被捕获,那么 catch 之后吞掉的话程序还能试着继续运行。发生 OutOfMemoryError 之后,只是当前这个线程申请更多的内存的时候不被 JVM 允许,所以会抛出 OutOfMemoryError 异常。当抛出 OutOfMemoryError 异常后,当前这个线程会被退出,它所占的内存会被 JVM 清理掉。

那么 JVM 为什么要这么设计呢?

答案是,Java 程序通常不是为了适应意外的异常而设计的,OOM 之后可能导致应用状态不一致,建议最好重启。

参考资料

  • Can the JVM recover from an OutOfMemoryError without a restart
  • JAVA发生OOM后还能运行么?

定时器 OOM(OutOfMemoryError) 了,其他线程受影响吗?

: » 定时器 OOM(OutOfMemoryError) 了,其他线程受影响吗?

原创文章,作者:dweifng,如若转载,请注明出处:https://blog.ytso.com/251861.html

(0)
上一篇 2022年5月3日
下一篇 2022年5月3日

相关推荐

发表回复

登录后才能评论