JAVA 內(nèi)存溢出案例匯總
寫在前面
作為程序員,多多少少都會遇到一些內(nèi)存溢出的場景,如果你還沒遇到,說明你工作的年限可能比較短,或者你根本就是個假程序員!哈哈,開個玩笑。今天,我們就以Java代碼的方式來列舉幾個典型的內(nèi)存溢出案例,希望大家在日常工作中,盡量避免寫這些low水平的代碼。
定義主類結(jié)構(gòu)
首先,我們創(chuàng)建一個名稱為BlowUpJVM的類,之后所有的案例實驗都是基于這個類進(jìn)行。如下所示。
public class BlowUpJVM { }
棧深度溢出
public static void testStackOverFlow(){ BlowUpJVM.testStackOverFlow(); }
棧不斷遞歸,而且沒有處理,所以虛擬機(jī)棧就不斷深入不斷深入,棧深度就這樣溢出了。
永久代內(nèi)存溢出
public static void testPergemOutOfMemory1(){ //方法一失敗 List<String> list = new ArrayList<String>(); while(true){ list.add(UUID.randomUUID().toString().intern()); } }
打算把String常量池堆滿,沒想到失敗了,JDK1.7后常量池放到了堆里,也能進(jìn)行垃圾回收了。
然后換種方式,使用cglib,用Class把老年代取堆滿
public static void testPergemOutOfMemory2(){ try { while (true) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(OOM.class); enhancer.setUseCache(false); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { return proxy.invokeSuper(obj, args); } }); enhancer.create(); } } catch (Exception e){ e.printStackTrace(); } }
虛擬機(jī)成功內(nèi)存溢出了,那JDK動態(tài)代理產(chǎn)生的類能不能溢出呢?
public static void testPergemOutOfMemory3(){ while(true){ final OOM oom = new OOM(); Proxy.newProxyInstance(oom.getClass().getClassLoader(), oom.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(oom, args); return result; } }); } }
事實表明,JDK動態(tài)代理差生的類不會造成內(nèi)存溢出,原因是:JDK動態(tài)代理產(chǎn)生的類信息,不會放到永久代中,而是放在堆中。
本地方法棧溢出
public static void testNativeMethodOutOfMemory(){ int j = 0; while(true){ Printer.println(j++); ExecutorService executors = Executors.newFixedThreadPool(50); int i=0; while(i++<10){ executors.submit(new Runnable() { public void run() { } }); } } }
這個的原理就是不斷創(chuàng)建線程池,而每個線程池都創(chuàng)建10個線程,這些線程池都是在本地方法區(qū)的,久而久之,本地方法區(qū)就溢出了。
JVM棧內(nèi)存溢出
public static void testStackOutOfMemory(){ while (true) { Thread thread = new Thread(new Runnable() { public void run() { while(true){ } } }); thread.start(); } }
線程的創(chuàng)建會直接在JVM棧中創(chuàng)建,但是本例子中,沒看到內(nèi)存溢出,主機(jī)先掛了,不是JVM掛了,真的是主機(jī)掛了,無論在mac還是在windows,都掛了。
溫馨提示,這個真的會死機(jī)的。
堆溢出
public static void testOutOfHeapMemory(){ List<StringBuffer> list = new ArrayList<StringBuffer>(); while(true){ StringBuffer B = new StringBuffer(); for(int i = 0 ; i < 10000 ; i++){ B.append(i); } list.add(B); } }
不斷往堆中塞新增的StringBuffer對象,堆滿了就直接溢出了。
測試案例完整代碼
public class BlowUpJVM { //棧深度溢出 public static void testStackOverFlow(){ BlowUpJVM.testStackOverFlow(); } //不能引起永久代溢出 public static void testPergemOutOfMemory1(){ //方法一失敗 List<String> list = new ArrayList<String>(); while(true){ list.add(UUID.randomUUID().toString().intern()); } } //永久代溢出 public static void testPergemOutOfMemory2(){ try { while (true) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(OOM.class); enhancer.setUseCache(false); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { return proxy.invokeSuper(obj, args); } }); enhancer.create(); } } catch (Exception e){ e.printStackTrace(); } } //不會引起永久代溢出 public static void testPergemOutOfMemory3(){ while(true){ final OOM oom = new OOM(); Proxy.newProxyInstance(oom.getClass().getClassLoader(), oom.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(oom, args); return result; } }); } } //本地方法棧溢出 public static void testNativeMethodOutOfMemory(){ int j = 0; while(true){ Printer.println(j++); ExecutorService executors = Executors.newFixedThreadPool(50); int i=0; while(i++<10){ executors.submit(new Runnable() { public void run() { } }); } } } //JVM內(nèi)存溢出 public static void testStackOutOfMemory(){ while (true) { Thread thread = new Thread(new Runnable() { public void run() { while(true){ } } }); thread.start(); } } //堆溢出 public static void testOutOfHeapMemory(){ List<StringBuffer> list = new ArrayList<StringBuffer>(); while(true){ StringBuffer B = new StringBuffer(); for(int i = 0 ; i < 10000 ; i++){ B.append(i); } list.add(B); } } }
最后,附上并發(fā)編程需要掌握的核心技能知識圖,祝大家在學(xué)習(xí)并發(fā)編程時,少走彎路。
以上就是JAVA 內(nèi)存溢出案例匯總的詳細(xì)內(nèi)容,更多關(guān)于JAVA 內(nèi)存溢出的資料請關(guān)注腳本之家其它相關(guān)文章!
- Java基礎(chǔ)詳解之內(nèi)存泄漏
- Java中的內(nèi)存泄漏
- 排查Java應(yīng)用內(nèi)存泄漏問題的步驟
- Java內(nèi)部類的實現(xiàn)原理與可能的內(nèi)存泄漏說明
- macOS上使用gperftools定位Java內(nèi)存泄漏問題及解決方案
- Java虛擬機(jī)內(nèi)存溢出與內(nèi)存泄漏
- 簡單了解JAVA內(nèi)存泄漏和溢出區(qū)別及聯(lián)系
- java內(nèi)存泄漏與內(nèi)存溢出關(guān)系解析
- 一次 Java 內(nèi)存泄漏的排查解決過程詳解
- Java基礎(chǔ)之堆內(nèi)存溢出的解決
- Java 內(nèi)存溢出的原因和解決方法
- Java虛擬機(jī)常見內(nèi)存溢出錯誤匯總
- Java內(nèi)存溢出實現(xiàn)原因及解決方案
- JAVA內(nèi)存溢出解決方案圖解
- Java基礎(chǔ)之內(nèi)存泄漏與溢出詳解
相關(guān)文章
idea啟動多個SpringBoot服務(wù)實例的最優(yōu)解決方法
啟動SpringBoot項目其實就是啟動Tomcat等服務(wù)容器,只要這個端口不同就能啟動多個服務(wù)實例了,本文主要介紹了idea啟動多個SpringBoot服務(wù)實例的最優(yōu)解決方法,感興趣的可以了解一下2024-05-05淺談Java代理(jdk靜態(tài)代理、動態(tài)代理和cglib動態(tài)代理)
下面小編就為大家?guī)硪黄獪\談Java代理(jdk靜態(tài)代理、動態(tài)代理和cglib動態(tài)代理)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-01-01Java的Jackson庫的使用及其樹模型的入門學(xué)習(xí)教程
這篇文章主要介紹了Java的Jackson庫的使用及其樹模型入門學(xué)習(xí)教程,Jackson庫通常被用來作Java對象和JSON的互相轉(zhuǎn)換,需要的朋友可以參考下2016-01-01