一個進程有3個線程尝抖,如果一個線程拋出OOM,其他兩個線程還能運行嗎漓踢?
答案是還能運行
不瞞大家說牵署,正在面試中,我遇到這一題喧半,我估計也會答錯奴迅,因為我初看這一題的時候,覺得是在考察JVM的內存結構挺据,我第一反應是OOM常見情況堆內存溢出取具,也就是下面的這種異常
java.lang.OutOfMemoryError:java heap space
多線程中棧與堆是公有還是私有的
在多線程環(huán)境下,每個線程擁有一個棧和一個程序計數器扁耐,棧和程序計數器用來保存線程執(zhí)行歷史和線程執(zhí)行狀態(tài)暇检,是線程私有的,堆是由用一個進程內多個線程共享的婉称。
測試代碼偽代碼如下:
一個線程去構造堆內存溢出块仆,每隔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,同進程下的其他線程還能繼續(xù)運行嗎悔据?
* @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線程還在執(zhí)行中科汗。使用jvisualvm監(jiān)控下藻烤。
設置的jvm參數:
-Xmx32m -Xms32m -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -verbose:gc -XX:+PrintGCDateStamps -Xloggc:E:/gc.log
分析gc日志,可以看出老年代的內存使用率達到99.79%头滔。內存使用率已經滿了怖亭。出現內存溢出。
上面是jvisualvm監(jiān)控堆內存變化的結果坤检,注意看圖上兴猩,拋出OOM的時間在14:56:54左右,重點關注這個時間點左右的曲線變化缀蹄。發(fā)現堆使用的數量突然間急速下滑峭跳,這代表這一點,當一個線程拋出OOM異常后缺前,它說占用的內存空間會全部被釋放掉蛀醉,從而不會影響其他線程的運行。
這個例子只是演示了堆內存溢出的情況衅码,如果是棧內存溢出拯刁,結論也是一樣的。