Java虛擬機(jī)常見(jiàn)內(nèi)存溢出錯(cuò)誤匯總
一、引言
從事java開(kāi)發(fā)的小伙伴在平時(shí)的開(kāi)發(fā)工作中,應(yīng)該會(huì)遇見(jiàn)各式各樣的異常和錯(cuò)誤,在實(shí)際工作中積累的異常或者錯(cuò)誤越多,趟過(guò)的坑越多,就會(huì)使我們編碼更加的健壯,就會(huì)本能地避開(kāi)很多嚴(yán)重的坑。以下介紹幾個(gè)Java虛擬機(jī)常見(jiàn)內(nèi)存溢出錯(cuò)誤。以此警示,避免生產(chǎn)血案。
二、模擬Java虛擬機(jī)常見(jiàn)內(nèi)存溢出錯(cuò)誤
1、內(nèi)存溢出之棧溢出錯(cuò)誤
package com.jayway.oom;
/**
* 棧溢出錯(cuò)誤
* 虛擬機(jī)參數(shù):-Xms10m -Xmx10m
* 拋出異常:Exception in thread "main" java.lang.StackOverflowError
*/
public class StackOverflowErrorDemo {
public static void main(String[] args) {
stackOverflowError();
}
private static void stackOverflowError() {
stackOverflowError();
}
}
2、內(nèi)存溢出之堆溢出錯(cuò)誤
package com.jayway.oom;
import java.util.Random;
/**
* 堆溢出錯(cuò)誤
* 虛擬機(jī)參數(shù):-Xmx10m -Xms10m
* 拋出異常:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
*/
public class JavaHeapSpaceErrorDemo {
public static void main(String[] args) {
String temp = "java";
//不斷地在堆中開(kāi)辟空間,創(chuàng)建對(duì)象,撐爆堆內(nèi)存
while (true) {
temp += temp + new Random().nextInt(111111111) + new Random().nextInt(222222222);
temp.intern();
}
}
}
3、內(nèi)存溢出之GC超過(guò)執(zhí)行限制錯(cuò)誤
package com.jayway.oom;
import java.util.ArrayList;
import java.util.List;
/**
* GC超過(guò)執(zhí)行限制錯(cuò)誤
* 虛擬機(jī)參數(shù):-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
* * 拋出異常:Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
* * 導(dǎo)致原因:GC回收時(shí)間過(guò)長(zhǎng)會(huì)拋出OutOfMemoryError,何為過(guò)長(zhǎng),即超過(guò)98%的cpu時(shí)間用來(lái)做GC垃圾回收
* 但是回收效果甚微,僅僅只有2%的CPU時(shí)間用來(lái)用戶(hù)程序的工作,這種狀態(tài)是很糟糕的,程序在不斷地GC
* 形成惡性循環(huán),CPU的使用率一直是滿(mǎn)負(fù)荷的,正經(jīng)活卻沒(méi)有干,這種情況虛擬機(jī)只好拋出錯(cuò)誤來(lái)終止程序的執(zhí)行
*
* 不斷地Full GC,事倍功微
* [Full GC (Ergonomics) [PSYoungGen: 2047K->2047K(2560K)] [ParOldGen: 7167K->7161K(7168K)] 9215K->9209K(9728K), [Metaspace: 3529K->3529K(1056768K)], 0.0291829 secs] [Times: user=0.08 sys=0.02, real=0.03 secs]
*/
public class GCOverheadErrorDemo {
public static void main(String[] args) {
int i = 0;
List<String> list = new ArrayList<>();
try {
while (true) {
list.add(String.valueOf(++i).intern());
}
} catch (Throwable e) {
System.out.println("*****************i:" + i);
e.printStackTrace();
throw e;
}
}
}
4、內(nèi)存溢出之直接內(nèi)存溢出錯(cuò)誤
package com.jayway.oom;
import java.nio.ByteBuffer;
/**
* 直接內(nèi)存溢出錯(cuò)誤
* 拋出異常:Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
* * 配置虛擬機(jī)參數(shù):-Xms10m -Xmx10m -XX:+PrintGCDetails -XX:MaxDirectMemorySize=5m
* * 導(dǎo)致原因:通常NIO程序經(jīng)常使用ByteBuffer來(lái)讀取或者寫(xiě)入數(shù)據(jù),這是一種基于通道(Channel)與緩沖區(qū)(Buffer)的IO方式,
* 它可以使用Native函數(shù)庫(kù)直接分配堆外內(nèi)存,然后通過(guò)一個(gè)存儲(chǔ)在java堆里面的DirectByteBuffer對(duì)象作為這塊內(nèi)存的引用,
* 這樣能子一些場(chǎng)景中顯著提高性能,因?yàn)楸苊饬嗽贘ava堆和Native內(nèi)存中來(lái)回復(fù)制數(shù)據(jù)。
*
* ByteBuffer.allocate(capability):分配JVM堆內(nèi)存,數(shù)據(jù)GC的管轄范圍,由于需要拷貝所以速度相對(duì)較慢
*
* ByteBuffer.allocate(capability):分配OS本地內(nèi)存,不屬于GC管轄范圍,由于不需要內(nèi)存拷貝,所以速度相對(duì)較快。
*
* 但是如果不斷分配本地內(nèi)存,堆內(nèi)存很少使用,那么JVM就不需要執(zhí)行GC,DirectByteBuffer對(duì)象就不會(huì)被回收,此時(shí)如果繼續(xù)分配堆外內(nèi)存,
* 可能堆外內(nèi)存已經(jīng)被耗光了無(wú)法繼續(xù)分配,此時(shí)程序就會(huì)拋出OutOfMemoryError,直接崩潰。
*
*/
public class DirectBufferMemoryErrorDemo {
public static void main(String[] args) {
//默認(rèn)JVM配置的最大直接內(nèi)存是總物理內(nèi)存的四分之一
long maxDirectMemory = sun.misc.VM.maxDirectMemory() / 1024 / 1024;
System.out.println("配置的maxDirectMemory:" + maxDirectMemory + "MB");
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024);
}
}
5、內(nèi)存溢出之無(wú)法創(chuàng)建新的本地線程
package com.jayway.oom;
/**
* 內(nèi)存溢出之無(wú)法創(chuàng)建新的本地線程
* 拋出異常:java.lang.OutOfMemoryError: unable to create new native thread
* * 描述:
* 高并發(fā)請(qǐng)求服務(wù)器時(shí),經(jīng)常出現(xiàn)java.lang.OutOfMemoryError: unable to create new native thread
* native thread異常與對(duì)應(yīng)的平臺(tái)有關(guān)
*
* 導(dǎo)致原因:
* 1、應(yīng)用程序創(chuàng)建了太多線程了,一個(gè)應(yīng)用進(jìn)程創(chuàng)建的線程數(shù)超過(guò)系統(tǒng)承載極限。
* 2、操作系統(tǒng)并不允許你的應(yīng)用進(jìn)程創(chuàng)建這么多的線程,linux系統(tǒng)默認(rèn)允許單個(gè)進(jìn)程可以創(chuàng)建的線程數(shù)是1024個(gè)
*
* 解決方法:
* 1、想辦法降低應(yīng)用進(jìn)程創(chuàng)建的線程數(shù)量,
* 2、如果應(yīng)用程序確實(shí)需要這么多線程,超過(guò)了linux系統(tǒng)的默認(rèn)1024個(gè)限制,可以通過(guò)修改linux服務(wù)器配置,提高這個(gè)閾值。
*
*/
public class UnableCreateNativeThreadErrorDemo {
public static void main(String[] args) {
for (int i = 0; true; i++) {
System.out.println("***************i:" + i);
//不斷得創(chuàng)建新線程,直到超過(guò)操作系統(tǒng)允許應(yīng)用進(jìn)程創(chuàng)建線程的極限
new Thread(() -> {
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
6、內(nèi)存溢出之元空間溢出錯(cuò)誤
package com.jayway.oom;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 元空間溢出錯(cuò)誤
* 拋出異常:java.lang.OutOfMemoryError: Metaspace
* * 設(shè)置虛擬機(jī)參數(shù):-XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=8m
* * 描述:Java8及以后的版本使用Metaspace來(lái)替代了永久代。metaspace是方法區(qū)在HotSpot中的實(shí)現(xiàn),它與持久代最大的區(qū)別在于
* Metaspace并不在虛擬機(jī)內(nèi)存中而是在本地內(nèi)存中。
*
* 元空間存儲(chǔ)了以下信息:
* 1、虛擬機(jī)加載的類(lèi)信息
* 2、常量池
* 3、靜態(tài)變量
* 4、即時(shí)編譯后的代碼
*
*/
public class MetaspaceErrorDemo {
static class OOMTest {
}
public static void main(String[] args) {
int count = 0;
try {
//cglib不斷創(chuàng)建類(lèi),模擬Metaspace空間溢出,我們不斷生成類(lèi)往元空間中灌,超過(guò)元空間大小后就會(huì)拋出元空間移除的錯(cuò)誤
while (true) {
count++;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMTest.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) {
System.out.println("************多少次后發(fā)生了異常:" + count);
e.printStackTrace();
}
}
}
以上就是Java虛擬機(jī)常見(jiàn)內(nèi)存溢出錯(cuò)誤匯總的詳細(xì)內(nèi)容,更多關(guān)于Java虛擬機(jī)內(nèi)存溢出的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Java虛擬機(jī)之類(lèi)加載
- java虛擬機(jī)之JVM調(diào)優(yōu)詳解
- Java虛擬機(jī)內(nèi)存區(qū)域劃分詳解
- 概述java虛擬機(jī)中類(lèi)的加載器及類(lèi)加載過(guò)程
- 深入了解Java虛擬機(jī)棧以及內(nèi)存模型
- 淺析Java虛擬機(jī)詳解之概述、對(duì)象生存法則
- Java跨平臺(tái)原理與虛擬機(jī)相關(guān)簡(jiǎn)介
- java虛擬機(jī)jvm方法區(qū)實(shí)例講解
- java虛擬機(jī)鉤子關(guān)閉函數(shù)addShutdownHook的操作
- java虛擬機(jī)是做什么用的
- 詳解Java 虛擬機(jī)垃圾收集機(jī)制
- Java虛擬機(jī)使用jvisualvm工具遠(yuǎn)程監(jiān)控tomcat內(nèi)存
- Java虛擬機(jī)執(zhí)行引擎知識(shí)總結(jié)
- Java啟用Azure Linux虛擬機(jī)診斷設(shè)置
- Java虛擬機(jī)內(nèi)存溢出與內(nèi)存泄漏
- java虛擬機(jī)創(chuàng)建失敗的原因整理
- Java內(nèi)存模型中的虛擬機(jī)棧原理分析
- Java基礎(chǔ)之創(chuàng)建虛擬機(jī)對(duì)象的過(guò)程詳細(xì)總結(jié)
相關(guān)文章
mybatis多數(shù)據(jù)源動(dòng)態(tài)切換的完整步驟
這篇文章主要給大家介紹了關(guān)于mybatis多數(shù)據(jù)源動(dòng)態(tài)切換的完整步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
解析Java實(shí)現(xiàn)設(shè)計(jì)模式六大原則之里氏替換原則
里氏替換原則是用來(lái)幫助我們?cè)诶^承關(guān)系中進(jìn)行父子類(lèi)的設(shè)計(jì)。它闡述了有關(guān)繼承的一些原則,也就是什么時(shí)候應(yīng)該使用繼承,什么時(shí)候不應(yīng)該使用繼承,以及其中蘊(yùn)含的原理。它是繼承復(fù)用的基礎(chǔ),反映了基類(lèi)與子類(lèi)之間的關(guān)系,是對(duì)開(kāi)閉原則的補(bǔ)充,對(duì)實(shí)現(xiàn)抽象化具體步驟的規(guī)范2021-06-06
Java中的NoClassDefFoundError報(bào)錯(cuò)含義解析
這篇文章主要為大家介紹了Java中的NoClassDefFoundError含義詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助2023-11-11
Java注解中@Component和@Bean的區(qū)別
這篇文章主要介紹了@Component和@Bean的區(qū)別,在這給大家簡(jiǎn)單介紹下作用對(duì)象不同:@Component 注解作用于類(lèi),而 @Bean 注解作用于方法,具體實(shí)例代碼參考下本文2024-03-03
Java后端WebSocket的Tomcat實(shí)現(xiàn)
這篇文章主要介紹了Java后端WebSocket的Tomcat實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06
Mybatis千萬(wàn)級(jí)數(shù)據(jù)查詢(xún)的解決方式,避免OOM問(wèn)題
這篇文章主要介紹了Mybatis千萬(wàn)級(jí)數(shù)據(jù)查詢(xún)的解決方式,避免OOM問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01

