面試官:工作中常見OOM有哪些?
共 9429字,需瀏覽 19分鐘
·
2024-04-19 18:19
今天接著線上問題這個話題,跟大家一起聊聊線上服務出現(xiàn)OOM的場景有哪些?希望對你會有所幫助。
1 堆內存OOM
堆內存OOM是最常見的OOM了。
出現(xiàn)堆內存OOM問題的異常信息如下:
java.lang.OutOfMemoryError: Java heap space
此OOM是由于JVM中heap的最大值,已經不能滿足需求了。
舉個例子:
public class HeapOOMTest {
public static void main(String[] args) {
List<HeapOOMTest> list = Lists.newArrayList();
while (true) {
list.add(new HeapOOMTest());
}
}
}
這里創(chuàng)建了一個list集合,在一個死循環(huán)中不停往里面添加對象。
執(zhí)行結果:出現(xiàn)了java.lang.OutOfMemoryError: Java heap space的堆內存溢出。
很多時候,excel一次導出大量的數(shù)據,獲取在程序中一次性查詢的數(shù)據太多,都可能會出現(xiàn)這種OOM問題。
我們在日常工作中一定要避免這種情況。
2 棧內存OOM
有時候,我們的業(yè)務系統(tǒng)創(chuàng)建了太多的線程,可能會導致棧內存OOM。
出現(xiàn)堆內存OOM問題的異常信息如下:
java.lang.OutOfMemoryError: unable to create new native thread
給大家舉個例子:
public class StackOOMTest {
public static void main(String[] args) {
while (true) {
new Thread().start();
}
}
}
使用一個死循環(huán)不停創(chuàng)建線程,導致系統(tǒng)產生了大量的線程。
執(zhí)行結果:如果實際工作中,出現(xiàn)這個問題,一般是由于創(chuàng)建的線程太多,或者設置的單個線程占用內存空間太大導致的。
建議在日常工作中,多用線程池,少自己創(chuàng)建線程,防止出現(xiàn)這個OOM。
3 棧內存溢出
我們在業(yè)務代碼中可能會經常寫一些遞歸調用,如果遞歸的深度超過了JVM允許的最大深度,可能會出現(xiàn)棧內存溢出問題。
出現(xiàn)棧內存溢出問題的異常信息如下:
java.lang.StackOverflowError
例如:
public class StackFlowTest {
public static void main(String[] args) {
doSamething();
}
private static void doSamething() {
doSamething();
}
}
執(zhí)行結果:
出現(xiàn)了java.lang.StackOverflowError棧溢出的錯誤。
我們在寫遞歸代碼時,一定要考慮遞歸深度。即使是使用parentId一層層往上找的邏輯,也最好加一個參數(shù)控制遞歸深度。防止因為數(shù)據問題導致無限遞歸的情況,比如:id和parentId的值相等。
4 直接內存OOM
直接內存不是虛擬機運行時數(shù)據區(qū)的一部分,也不是《Java虛擬機規(guī)范》中定義的內存區(qū)域。
它來源于NIO,通過存在堆中的DirectByteBuffer操作Native內存,是屬于堆外內存,可以直接向系統(tǒng)申請的內存空間。
出現(xiàn)直接內存OOM問題時異常信息如下:
java.lang.OutOfMemoryError: Direct buffer memory
例如下面這樣的:
public class DirectOOMTest {
private static final int BUFFER = 1024 * 1024 * 20;
public static void main(String[] args) {
ArrayList<ByteBuffer> list = new ArrayList<>();
int count = 0;
try {
while (true) {
// 使用直接內存
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
list.add(byteBuffer);
count++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
System.out.println(count);
}
}
}
執(zhí)行結果:
會看到報出來java.lang.OutOfMemoryError: Direct buffer memory直接內存空間不足的異常。
5 GC OOM
GC OOM是由于JVM在GC時,對象過多,導致內存溢出,建議調整GC的策略。
出現(xiàn)GC OOM問題時異常信息如下:
java.lang.OutOfMemoryError: GC overhead limit exceeded
為了方便測試,我先將idea中的最大和最小堆大小都設置成10M:
-Xmx10m -Xms10m
例如下面這個例子:
public class GCOverheadOOM {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < Integer.MAX_VALUE; i++) {
executor.execute(() -> {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
});
}
}
}
執(zhí)行結果:
出現(xiàn)這個問題是由于JVM在GC的時候,對象太多,就會報這個錯誤。
我們需要改變GC的策略。
在老代80%時就是開始GC,并且將-XX:SurvivorRatio(-XX:SurvivorRatio=8)和-XX:NewRatio(-XX:NewRatio=4)設置的更合理。
6 元空間OOM
JDK8之后使用Metaspace來代替永久代,Metaspace是方法區(qū)在HotSpot中的實現(xiàn)。
Metaspace不在虛擬機內存中,而是使用本地內存也就是在JDK8中的ClassMetadata,被存儲在叫做Metaspace的native memory。
出現(xiàn)元空間OOM問題時異常信息如下:
java.lang.OutOfMemoryError: Metaspace
為了方便測試,我修改一下idea中的JVM參數(shù),增加下面的配置:
-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
指定了元空間和最大元空間都是10M。
接下來,看看下面這個例子:
public class MetaspaceOOMTest {
static class OOM {
}
public static void main(String[] args) {
int i = 0;
try {
while (true) {
i++;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOM.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
return methodProxy.invokeSuper(o, args);
}
});
enhancer.create();
}
} catch (Throwable e) {
e.printStackTrace();
}
}
}
執(zhí)行結果:程序最后會報java.lang.OutOfMemoryError: Metaspace的元空間OOM。
這個問題一般是由于加載到內存中的類太多,或者類的體積太大導致的。
好了,今天的內容先分享到這里,下一篇文章重點給大家講講,如何用工具定位OOM問題,敬請期待。
課程推薦
《Java 面試突擊訓練營》是有著 14 年工作經驗(前 360 開發(fā)工程師),9 年面試官經驗的我,花費 4 年時間打磨完成的一門視頻面試課。
整個課程從 Java 基礎到微服務 Spring Cloud、從實際開發(fā)問題到場景題應有盡有,包含模塊如下:
訓練營系統(tǒng)的帶領大家把 Java 常見的面試題過一遍,遇到一個問題,把這個問題相關的內容都給大家講明白,并且視頻支持永久觀看和一直更新。并且面試訓練營還提供 10 大就業(yè)服務。
上完訓練營的課程之后,基本可以應對目前市面上絕大部分公司的面試了,想要了解詳情,加我微信:GG_Stone【備注:訓練營】
