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();
}
棧不斷遞歸,而且沒有處理,所以虛擬機棧就不斷深入不斷深入,棧深度就這樣溢出了。
永久代內(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();
}
}
虛擬機成功內(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)存溢出,主機先掛了,不是JVM掛了,真的是主機掛了,無論在mac還是在windows,都掛了。
溫馨提示,這個真的會死機的。
堆溢出
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虛擬機內(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虛擬機常見內(nèi)存溢出錯誤匯總
- Java內(nèi)存溢出實現(xiàn)原因及解決方案
- JAVA內(nèi)存溢出解決方案圖解
- Java基礎(chǔ)之內(nèi)存泄漏與溢出詳解
相關(guān)文章
解決java.lang.NoClassDefFoundError:lombok/Data報錯問題
在Java開發(fā)中,使用Lombok庫簡化代碼非常普遍,今天在啟動拉取的git代碼時,遇到了java.lang.NoClassDefFoundError:lombok/Data的報錯,經(jīng)過檢查,發(fā)現(xiàn)錯誤的原因是將Date誤寫為Data,且錯誤地引用了lombok.Data包2024-09-09
Java反射機制,反射相關(guān)API,反射API使用方式(反射獲取實體類字段名和注解值)
這篇文章主要介紹了Java反射機制,反射相關(guān)API,反射API使用方式(反射獲取實體類字段名和注解值),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07
Spring Boot 2.x基礎(chǔ)教程之配置元數(shù)據(jù)的應(yīng)用
這篇文章主要介紹了Spring Boot 2.x基礎(chǔ)教程之配置元數(shù)據(jù)的應(yīng)用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01
SpringBoot+Thymeleaf靜態(tài)資源的映射規(guī)則說明
這篇文章主要介紹了SpringBoot+Thymeleaf靜態(tài)資源的映射規(guī)則說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
SpringBoot生產(chǎn)環(huán)境和測試環(huán)境配置分離的教程詳解
這篇文章主要介紹了SpringBoot生產(chǎn)環(huán)境和測試環(huán)境配置分離的教程詳解,需要的朋友可以參考下2020-08-08

