new arraylist内存_如何避免内部类中的内存泄漏
我先假設讀者已經(jīng)熟悉在Java代碼中使用嵌套類的基礎知識。在本文里,我將展示嵌套類的陷阱,內(nèi)部類在JVM中引起內(nèi)存泄漏和內(nèi)存不足錯誤的地方。之所以會發(fā)生這種類型的內(nèi)存泄漏,是因為內(nèi)部類必須始終能夠訪問其外部類。從簡單的嵌套過程到內(nèi)存不足錯誤(并可能關閉JVM)是一個過程。我們一步步看他是如何產(chǎn)生的。
步驟1:內(nèi)部類引用其外部類
內(nèi)部類的任何實例都包含對其外部類的隱式引用。例如,考慮以下帶有嵌套的EnclosedClass非靜態(tài)成員類的EnclosingClass聲明:
public class EnclosingClass
{
public class EnclosedClass
{
}
}
為了更好地理解這種連接,我們可以將上面的源代碼(javac EnclosingClass.java)編譯為EnclosingClass.class和EnclosingClass $ EnclosedClass.class,然后檢查后者的類文件。
JDK包含用于反匯編類文件的javap(Java打印)工具。在命令行上,使javap帶有EnclosingClass $ EnclosedClass,如下所示:
javap EnclosingClass$EnclosedClass
我們可以觀察到以下輸出,該輸出揭示了一個隱含的 final的 EnclosingClass this $ 0字段,該字段包含對EnclosingClass的引用:
Compiled from "EnclosingClass.java"
public class EnclosingClass$EnclosedClass {
final EnclosingClass this$0;
public EnclosingClass$EnclosedClass(EnclosingClass);
}
步驟2:構造函數(shù)獲取封閉的類引用
上面的輸出顯示了帶有EnclosingClass參數(shù)的構造函數(shù)。使用-v(詳細)選項執(zhí)行javap,可以觀察到構造函數(shù)在this $ 0字段中保存了EnclosingClass對象引用:
final EnclosingClass this$0;
descriptor: LEnclosingClass;
flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC
public EnclosingClass$EnclosedClass(EnclosingClass);
descriptor: (LEnclosingClass;)V
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #1 // Field this$0:LEnclosingClass;
5: aload_0
6: invokespecial #2 // Method java/lang/Object."":()V
9: return
LineNumberTable:
line 3: 0
步驟3:聲明一個新方法
接下來,我們另一個類中聲明一個方法,實例化EnclosingClass,然后實例化EnclosedClass。例如:
EnclosingClass ec = newEnclosingClass();
ec.newEnclosedClass();
下面的javap輸出顯示了此源代碼的字節(jié)碼轉換。第18行顯示對EnclosingClass $ EnclosedClass(EnclosingClass)的調(diào)用。
0: new #2 // class EnclosingClass
3: dup
4: invokespecial #3 // Method EnclosingClass."":()V
7: astore_1
8: new #4 // class EnclosingClass$EnclosedClass
11: dup
12: aload_1
13: dup
14: invokestatic #5 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
17: pop
18: invokespecial #6 // Method EnclosingClass$EnclosedClass."":(LEnclosingClass;)V
21: pop
22: return
內(nèi)存泄漏的解剖
在以上示例中,根據(jù)應用程序代碼,可能會耗盡內(nèi)存并收到內(nèi)存不足錯誤,從而導致JVM終止。下面的清單演示了這種情況。
import java.util.ArrayList;
class EnclosingClass
{
private int[] data;
public EnclosingClass(int size)
{
data = new int[size];
}
class EnclosedClass
{
}
EnclosedClass getEnclosedClassObject()
{
return new EnclosedClass();
}
}
public class MemoryLeak
{
public static void main(String[] args)
{
ArrayList al = new ArrayList<>();
int counter = 0;
while (true)
{
al.add(new EnclosingClass(100000).getEnclosedClassObject());
System.out.println(counter++);
}
}
}
EnclosingClass聲明一個引用整數(shù)數(shù)組的私有數(shù)據(jù)字段。數(shù)組的大小傳遞給此類的構造函數(shù),并實例化該數(shù)組。
EnclosingClass還聲明EnclosedClass,一個嵌套的非靜態(tài)成員類,以及一個實例化EnclosedClass的方法,并返回此實例。
MemoryLeak的main()方法首先創(chuàng)建一個java.util.ArrayList來存儲EnclosingClass.EnclosedClass對象。現(xiàn)在,觀察內(nèi)存泄漏是如何發(fā)生的。
將計數(shù)器初始化為0后,main()進入無限while循環(huán),該循環(huán)重復實例化EnclosedClass并將其添加到數(shù)組列表中。然后打印(或遞增)計數(shù)器。
每個存儲的EnclosedClass對象都維護對其外部對象的引用,該對象引用100,000個32位整數(shù)(或400,000字節(jié))的數(shù)組。在對內(nèi)部對象進行垃圾收集之前,無法對外部對象進行垃圾收集。最終,該應用程序?qū)⒑谋M內(nèi)存。
javac MemoryLeak.java
java MemoryLeak
我們將觀察到如下輸出(當然在不同的機器上,最后的數(shù)字可能不一樣):
7639
7640
7641
7642
7643
7644
7645
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at EnclosingClass.(MemoryLeak.java:9)
at MemoryLeak.main(MemoryLeak.java:30)
往期精選
CHOICENESS
是兄弟,就來“kan”我總結
以上是生活随笔為你收集整理的new arraylist内存_如何避免内部类中的内存泄漏的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android pda出入库管理,出入库
- 下一篇: 汉字的ascii码值范围_ASCII代码