來源:https://knife.blog.csdn.net/article/details/124946774
今天給大家分享一種,Java內部類使用不當導致的記憶體泄露問題,最終導致記憶體溢位!希望能夠幫助到大家!
簡介
「說明」
本文介紹 Java 內部類持有外部類導致記憶體泄露的原因以及其解決方案,
「為什么內部類持有外部類會導致記憶體泄露?」
非靜態內部類會持有外部類,如果有地方參考了這個非靜態內部類,會導致外部類也被參考,垃圾回收時無法回收這個外部類(即使外部類已經沒有其他地方在使用了),
「解決方案」
- 不要讓其他的地方持有這個非靜態內部類的參考,直接在這個非靜態內部類執行業務,
- 將非靜態內部類改為靜態內部類,內部類改為靜態的之后,它所參考的物件或屬性也必須是靜態的,所以靜態內部類無法獲得外部物件的參考,只能從 JVM 的 Method Area(方法區)獲取到static型別的參考,
為什么要持有外部類
Java 語言中,非靜態內部類的主要作用有兩個:
- 當內部類只在外部類中使用時,匿名內部類可以讓外部不知道它的存在,從而減少了代碼的維護作業,
- 當內部類持有外部類時,它就可以直接使用外部類中的變數了,這樣可以很方便的完成呼叫,如下代碼所示:
package org.example.a;
class Outer{
private String outerName = "Tony";
class Inner{
private String name;
public Inner() {
this.name = outerName;
}
}
Inner createInner() {
return new Inner();
}
}
public class Demo {
public static void main(String[] args) {
Outer.Inner inner = new Outer().createInner();
System.out.println(inner);
}
}
但是,靜態內部類就無法持有外部類和其非靜態欄位了,另外,最新 Java 面試題整理:https://www.javastack.cn/mst/
比如下邊這樣就會報錯
package org.example.a;
class Outer{
private String outerName = "Tony";
static class Inner{
private String name;
public Inner() {
this.name = outerName;
}
}
Inner createInner() {
return new Inner();
}
}
public class Demo {
public static void main(String[] args) {
Outer.Inner inner = new Outer().createInner();
System.out.println(inner);
}
}
報錯:

實體:持有外部類
「代碼」
package org.example.a;
class Outer{
class Inner {
}
Inner createInner() {
return new Inner();
}
}
public class Demo {
public static void main(String[] args) {
Outer.Inner inner = new Outer().createInner();
System.out.println(inner);
}
}
「斷點除錯」
可以看到:內部類持有外部類的物件的參考,是以“this$0”這個欄位來保存的,

實體:不持有外部類
「代碼」
package org.example.a;
class Outer{
static class Inner {
}
Inner createInner() {
return new Inner();
}
}
public class Demo {
public static void main(String[] args) {
Outer.Inner inner = new Outer().createInner();
System.out.println(inner);
}
}
更多 Java 教程及示例:https://github.com/javastacks/javastack
「斷點除錯」
可以發現:內部類不再持有外部類了,

實體:記憶體泄露
「簡介」
若內部類持有外部類的參考,對內部類的使用很多時,會導致外部類數目很多,此時,就算是外部類的資料沒有被用到,外部類的資料所占空間也不會被釋放,
本處在外部類存放大量的資料來模擬,
「代碼」
package org.example.a;
import java.util.ArrayList;
import java.util.List;
class Outer{
private int[] data;
public Outer(int size) {
this.data = https://www.cnblogs.com/javastack/p/new int[size];
}
class Innner{
}
Innner createInner() {
return new Innner();
}
}
public class Demo {
public static void main(String[] args) {
List
「測驗」
可以看到:運行了八千多次的時候就記憶體溢位了,

我換了一臺 mac 電腦,4000 多就記憶體溢位了,

不會記憶體泄露的方案
「簡介」
內部類改為靜態的之后,它所參考的物件或屬性也必須是靜態的,所以靜態內部類無法獲得外部物件的參考,只能從 JVM 的 Method Area(方法區)獲取到 static 型別的參考,
「代碼」
package org.example.a;
import java.util.ArrayList;
import java.util.List;
class Outer{
private int[] data;
public Outer(int size) {
this.data = https://www.cnblogs.com/javastack/p/new int[size];
}
static class Inner {
}
Inner createInner() {
return new Inner();
}
}
public class Demo {
public static void main(String[] args) {
List
「測驗」
可以發現:回圈了四十多萬次都沒有記憶體溢位,

近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
2.勁爆!Java 協程要來了,,,
3.Spring Boot 2.x 教程,太全了!
4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/538116.html
標籤:Java
下一篇:java 基礎——函式(方法)
