工作中最常見的6種OOM問題
往期熱門文章:
1、千萬不要濫用Stream.toList(),有坑! 2、強烈建議你不要再使用Date類了?。。?/a> 3、IDEA 接口調(diào)試神器,賊好用! 4、Java內(nèi)部類有坑,100%內(nèi)存泄露! 5、盤點Lombok的幾個騷操作 5、被問懵了,加密后的數(shù)據(jù)如何進行模糊查詢?
前言
1 堆內(nèi)存OOM
java.lang.OutOfMemoryError: Java heap space
public class HeapOOMTest {
public static void main(String[] args) {
List<HeapOOMTest> list = Lists.newArrayList();
while (true) {
list.add(new HeapOOMTest());
}
}
}

2 棧內(nèi)存OOM
java.lang.OutOfMemoryError: unable to create new native thread
public class StackOOMTest {
public static void main(String[] args) {
while (true) {
new Thread().start();
}
}
}

建議在日常工作中,多用線程池,少自己創(chuàng)建線程,防止出現(xiàn)這個OOM。
3 棧內(nèi)存溢出
遞歸調(diào)用,如果遞歸的深度超過了JVM允許的最大深度,可能會出現(xiàn)棧內(nèi)存溢出問題。
java.lang.StackOverflowError
public class StackFlowTest {
public static void main(String[] args) {
doSamething();
}
private static void doSamething() {
doSamething();
}
}

我們在寫遞歸代碼時,一定要考慮遞歸深度。即使是使用parentId一層層往上找的邏輯,也最好加一個參數(shù)控制遞歸深度。防止因為數(shù)據(jù)問題導致無限遞歸的情況,比如:id和parentId的值相等。
4 直接內(nèi)存OOM
直接內(nèi)存不是虛擬機運行時數(shù)據(jù)區(qū)的一部分,也不是《Java虛擬機規(guī)范》中定義的內(nèi)存區(qū)域。
NIO,通過存在堆中的DirectByteBuffer操作Native內(nèi)存,是屬于堆外內(nèi)存,可以直接向系統(tǒng)申請的內(nèi)存空間。
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) {
// 使用直接內(nèi)存
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
list.add(byteBuffer);
count++;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
System.out.println(count);
}
}
}

5 GC OOM
GC OOM是由于JVM在GC時,對象過多,導致內(nèi)存溢出,建議調(diào)整GC的策略。
java.lang.OutOfMemoryError: GC overhead limit exceeded
-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) {
}
});
}
}
}

6 元空間OOM
JDK8之后使用Metaspace來代替永久代,Metaspace是方法區(qū)在HotSpot中的實現(xiàn)。
ClassMetadata,被存儲在叫做Metaspace的native memory。
java.lang.OutOfMemoryError: Metaspace
-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=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();
}
}
}

往期熱門文章:
1、中國程序員獨立開發(fā)9年、最受歡迎的開源Redis客戶端,被Redis公司收購了! 2、我在代碼里面故意留個漏洞,違法嗎? 3、一個現(xiàn)代化輕量級的跨平臺 Redis 桌面客戶端,支持 Mac、Windows 和 Linux 4、能用到“退休”的 600條 Linux 命令,可以解決日常99%的問題~ 5、工作六年,看到這樣的代碼,內(nèi)心五味雜陳... 6、拒絕寫重復代碼,試試這套開源的 SpringBoot 組件 7、一次生產(chǎn)事故,來來回回搞了一個月,人麻了! 8、面試官:Git 如何撤回已 Push 的代碼?問倒一大片。。。 9、SpringBoot 如何快速過濾出一次請求的所有日志? 10、千萬不要把 Request 傳遞到異步線程里面!有坑! 10、別再用 offset 和 limit 分頁了,性能太差!
評論
圖片
表情
