OOM不会导致JVM退出

问题来源

一次生产事故,由于一次性从数据库查询过多数据导致线程 OOM:Java heap space 异常(千万级表,JVM堆内存2G),但是在线程OOM发生时,java进程却没有立即挂掉。

##OOM与异常
说到底OutOfMemoryError也只是一个java中的异常而已,属于Error一系非检查异常:

Object
	Throwable
		Error
			VirtualMachineError
				OutOfMemoryError

堆内存不够与异常的关系

线程发生OOM Java heap space,首先是堆空间不够了,然后再由jvm在申请分配空间的方法调用上抛出OOM异常。
对于线程,它会像处理普通异常一样,处理OutOfMemoryError。

实例

package org.example;

import com.sun.javafx.scene.control.skin.TableHeaderRow;

import java.util.ArrayList;

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
    public static void main(String[] args) throws InterruptedException{
        //TIP Press <shortcut actionId="ShowIntentionActions"/> with your caret at the highlighted text
        // to see how IntelliJ IDEA suggests fixing it.
        System.out.printf("Hello and welcome!");

        System.out.println("JVM从OS获取的 最大 内存" + Runtime.getRuntime().maxMemory() / 1024 / 1024 + "M");
        System.out.println("JVM从OS获取的 当前 内存" + Runtime.getRuntime().totalMemory() / 1024 / 1024 + "M");
        System.out.println("JVM从OS获取的 但空闲 内存" + Runtime.getRuntime().freeMemory() / 1024 / 1024 + "M");

        // 创建线程
        new Thread(() -> {
            ArrayList<byte[]> bytes = new ArrayList<>();
            for (int i = 0; i < 2000; i++) {
                byte[] bytes1 = new byte[3 * 1024 * 1024];
                bytes.add(bytes1);
                System.out.println(Thread.currentThread().getName()+":JVM从OS获取的 当前 内存" + Runtime.getRuntime().totalMemory() / 1024 / 1024 + "M");
            }
        }).start();

        // 创建线程
        new Thread(() -> {
            ArrayList<byte[]> bytes = new ArrayList<>();
            for (int i = 0; i < 2000; i++) {
                byte[] bytes1 = new byte[3 * 1024 * 1024];
                bytes.add(bytes1);
                System.out.println(Thread.currentThread().getName()+":JVM从OS获取的 当前 内存" + Runtime.getRuntime().totalMemory() / 1024 / 1024 + "M");
            }
        }).start();

        while (true){
            System.out.println(Thread.currentThread().getName() + " continuing...");
            Thread.sleep(1000L);
        }
    }
}

结果:

##本机64位,16G内存,默认最大堆3600M
JVM从OS获取的 最大 内存3600M
JVM从OS获取的 当前 内存243M
JVM从OS获取的 但空闲 内存237M
main continuing...

##2个线程分别开始创建byte数组,占用内存 
Thread-0:JVM从OS获取的 当前 内存307M
Thread-1:JVM从OS获取的 当前 内存307M
Thread-1:JVM从OS获取的 当前 内存307M
Thread-0:JVM从OS获取的 当前 内存307M


##JVM增长到极限,Thread-1先报OOM
Thread-0:JVM从OS获取的 当前 内存3366M
Thread-0:JVM从OS获取的 当前 内存3366M
Exception in thread "Thread-1" java.lang.OutOfMemoryError: Java heap space
	at org.example.Main.lambda$main$1(Main.java:39)
	at org.example.Main$$Lambda$2/1828972342.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:750)
Thread-0:JVM从OS获取的 当前 内存3366M
Thread-0:JVM从OS获取的 当前 内存3366M

#Thread-1失败终止后,起引用的对象也就可以GC了,Thread-0又获取了好多内存,直到OOM
Thread-0:JVM从OS获取的 当前 内存3616M
Thread-0:JVM从OS获取的 当前 内存3616M
Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space
	at org.example.Main.lambda$main$0(Main.java:29)
	at org.example.Main$$Lambda$1/1989780873.run(Unknown Source)
	at java.lang.Thread.run(Thread.java:750)
main continuing...
main continuing...
main continuing...

结论

1、OOM是在线程上发生的,会被当做一般异常处理,不会导致JVM的退出;
2、多线程公用JVM,一个线程终止GC后,内存重新给其他线程分配。

相关推荐

  1. OOM导致JVM退出

    2024-05-25 18:12:41       9 阅读
  2. 为什么数据库字符编码一致导致索引失效

    2024-05-25 18:12:41       11 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-25 18:12:41       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-25 18:12:41       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-25 18:12:41       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-25 18:12:41       18 阅读

热门阅读

  1. 「Electron」Electron 应用程序详解

    2024-05-25 18:12:41       11 阅读
  2. 什么是UDP服务器?

    2024-05-25 18:12:41       8 阅读
  3. 根据标签名递归读取xml字符串中element

    2024-05-25 18:12:41       9 阅读
  4. 网络协议——有状态协议和无状态协议

    2024-05-25 18:12:41       9 阅读
  5. C#拼接xml

    2024-05-25 18:12:41       10 阅读
  6. xmlhttp中withcredential用法

    2024-05-25 18:12:41       11 阅读
  7. 使用HTTP客户端在Python中进行网页抓取——笔记

    2024-05-25 18:12:41       14 阅读
  8. Vue2常用的组件通信方式有几种

    2024-05-25 18:12:41       14 阅读
  9. STL源码看书笔记(1)——代码解析

    2024-05-25 18:12:41       9 阅读