一个进程有3个线程,如果一个线程抛出OOM,其他两个线程还能运行吗?
答案是还能运行
不瞒大家说,正在面试中,我遇到这一题,我估计也会答错,因为我初看这一题的时候,觉得是在考察JVM的内存结构,我第一反应是OOM常见情况堆内存溢出,也就是下面的这种异常
java.lang.OutOfMemoryError:java heap space
多线程中栈与堆是公有还是私有的
在多线程环境下,每个线程拥有一个栈和一个程序计数器,栈和程序计数器用来保存线程执行历史和线程执行状态,是线程私有的,堆是由用一个进程内多个线程共享的。
测试代码伪代码如下:
一个线程去构造堆内存溢出,每隔ls申请一次堆内存。
package com.ypb.oom;
import com.google.common.collect.Lists;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
/**
* @className ThreadOOMTest
* @description 测试一个线程出现OOM,同进程下的其他线程还能继续运行吗?
* @author yangpengbing
* @date 22:12 2018/12/19
* @version 1.0.0
*/
@Slf4j
public class ThreadOOMTest {
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
int m = 1024 * 1024;
String name = "oom-thread";
new Thread(() -> {
List<byte[]> bytes = Lists.newArrayList();
while (true) {
show(format(formatter));
bytes.add(new byte[m]);
sleep();
}
}, name).start();
name = "not-oom-thread";
new Thread(()->{
while (true) {
show(format(formatter));
sleep();
}
}, name).start();
}
/**
* 控制台输出时间和线程名称
* @param msg
*/
private static void show(String msg) {
System.out.println(msg);
}
/**
* 线程休眠1s
*/
private static void sleep() {
try {
TimeUnit.SECONDS.sleep(1L);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 格式化输出的信息
* @param formatter
* @return
*/
private static String format(DateTimeFormatter formatter) {
return String.format("data {%s}, thread {%s}", LocalDateTime.now().format(formatter), Thread.currentThread().getName());
}
}
控制台输出的结果:
从日志中可以看出,线程oom-thread线程溢出了,其他线程not-oom-thread线程还在执行中。使用jvisualvm监控下。
设置的jvm参数:
-Xmx32m -Xms32m -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -verbose:gc -XX:+PrintGCDateStamps -Xloggc:E:/gc.log
分析gc日志,可以看出老年代的内存使用率达到99.79%。内存使用率已经满了。出现内存溢出。
上面是jvisualvm监控堆内存变化的结果,注意看图上,抛出OOM的时间在14:56:54左右,重点关注这个时间点左右的曲线变化。发现堆使用的数量突然间急速下滑,这代表这一点,当一个线程抛出OOM异常后,它说占用的内存空间会全部被释放掉,从而不会影响其他线程的运行。
这个例子只是演示了堆内存溢出的情况,如果是栈内存溢出,结论也是一样的。