以Java代碼的方式總結(jié)幾個(gè)典型的內(nèi)存溢出案例
一、圖示
我們先來看看今天要介紹哪些內(nèi)存溢出案例,這里總結(jié)了一張圖,如下所示。

二、定義主類結(jié)構(gòu)
首先,我們創(chuàng)建一個(gè)名稱為BlowUpJVM的類,之后所有的案例實(shí)驗(yàn)都是基于這個(gè)類進(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動(dòng)態(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;
}
});
}
}
事實(shí)表明,JDK動(dòng)態(tài)代理差生的類不會(huì)造成內(nèi)存溢出,原因是:JDK動(dòng)態(tài)代理產(chǎn)生的類信息,不會(huì)放到永久代中,而是放在堆中。
五、本地方法棧溢出
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() {
}
});
}
}
}
這個(gè)的原理就是不斷創(chuàng)建線程池,而每個(gè)線程池都創(chuàng)建10個(gè)線程,這些線程池都是在本地方法區(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)建會(huì)直接在JVM棧中創(chuàng)建,但是本例子中,沒看到內(nèi)存溢出,主機(jī)先掛了,不是JVM掛了,真的是主機(jī)掛了,無論在mac還是在windows,都掛了。
溫馨提示,這個(gè)真的會(huì)死機(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對(duì)象,堆滿了就直接溢出了。
八、測(cè)試案例完整代碼
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();
}
}
//不會(huì)引起永久代溢出
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);
}
}
}
到此這篇關(guān)于以Java代碼的方式列舉幾個(gè)典型的內(nèi)存溢出案例總結(jié)的文章就介紹到這了,更多相關(guān)Java內(nèi)存溢出內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java selenium處理極驗(yàn)滑動(dòng)驗(yàn)證碼示例
本篇文章主要介紹了Java selenium處理極驗(yàn)滑動(dòng)驗(yàn)證碼示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10
關(guān)于springcloud報(bào)錯(cuò)報(bào)UnsatisfiedDependencyException的問題
這篇文章主要介紹了關(guān)于springcloud報(bào)錯(cuò)報(bào)UnsatisfiedDependencyException的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11
SpringBoot通過AOP與注解實(shí)現(xiàn)入?yún)⑿r?yàn)詳情
這篇文章主要介紹了SpringBoot通過AOP與注解實(shí)現(xiàn)入?yún)⑿r?yàn)詳情,文章從相關(guān)問題展開全文內(nèi)容詳情,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-05-05
java面向?qū)ο缶幊讨匾拍罾^承和多態(tài)示例解析
這篇文章主要為大家介紹了java面向?qū)ο缶幊痰膬蓚€(gè)重要概念繼承和多態(tài)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05
idea2019導(dǎo)入maven項(xiàng)目中的某些問題及解決方法
這篇文章主要介紹了idea2019導(dǎo)入maven項(xiàng)目中的某些問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08

