一個進程有3個線程,如果一個線程拋出OOM,其他兩個線程還能運行嗎?
答案是還能運行
不瞞大家說,正在面試中,我遇到這一題,我估計也會答錯,因為我初看這一題的時候,覺得是在考察JVM的內存結構,我第一反應是OOM常見情況堆內存溢出,也就是下面的這種異常
<code>java
.lang
.OutOfMemoryError
:java
heap
space
/<code>
多線程中棧與堆是公有還是私有的
<code>在多線程環境下,每個線程擁有一個棧和一個程序計數器,棧和程序計數器用來保存線程執行歷史和線程執行狀態,是線程私有的,堆是由用一個進程內多個線程共享的。 /<code>
測試代碼偽代碼如下:
一個線程去構造堆內存溢出,每隔ls申請一次堆內存。
<code>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; 4jpublic
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(); }private
static
void
show
(String msg)
{ System.out.println(msg); }private
static
void
sleep
()
{try
{ TimeUnit.SECONDS.sleep(1L
); }catch
(Exception e) { e.printStackTrace(); } }private
static
Stringformat
(DateTimeFormatter formatter)
{return
String.format("data {%s}, thread {%s}"
, LocalDateTime.now().format(formatter), Thread.currentThread().getName()); } } /<code>
控制檯輸出的結果:
從日誌中可以看出,線程oom-thread線程溢出了,其他線程not-oom-thread線程還在執行中。使用jvisualvm監控下。
設置的jvm參數:
<code>-Xmx32m
-Xms32m
-XX
:+UseConcMarkSweepGC
-XX
:+PrintGCDetails
-verbose
:gc
-XX
:+PrintGCDateStamps
-Xloggc
:E
:/gc
.log
/<code>
1
分析gc日誌,可以看出老年代的內存使用率達到99.79%。內存使用率已經滿了。出現內存溢出。
上面是jvisualvm監控堆內存變化的結果,注意看圖上,拋出OOM的時間在14:56:54左右,重點關注這個時間點左右的曲線變化。發現堆使用的數量突然間急速下滑,這代表這一點,當一個線程拋出OOM異常後,它說佔用的內存空間會全部被釋放掉,從而不會影響其他線程的運行。
這個例子只是演示了堆內存溢出的情況,如果是棧內存溢出,結論也是一樣的。