「說明」
本文介紹 Java 內(nèi)部類持有外部類導(dǎo)致內(nèi)存泄露的原因以及其解決方案。
「為什么內(nèi)部類持有外部類會導(dǎo)致內(nèi)存泄露?」
非靜態(tài)內(nèi)部類會持有外部類,如果有地方引用了這個非靜態(tài)內(nèi)部類,會導(dǎo)致外部類也被引用,垃圾回收時無法回收這個外部類(即使外部類已經(jīng)沒有其他地方在使用了)。
「解決方案」
不要讓其他的地方持有這個非靜態(tài)內(nèi)部類的引用,直接在這個非靜態(tài)內(nèi)部類執(zhí)行業(yè)務(wù)。
將非靜態(tài)內(nèi)部類改為靜態(tài)內(nèi)部類。內(nèi)部類改為靜態(tài)的之后,它所引用的對象或?qū)傩砸脖仨毷庆o態(tài)的,所以靜態(tài)內(nèi)部類無法獲得外部對象的引用,只能從 JVM 的 Method Area(方法區(qū))獲取到static類型的引用。
為什么要持有外部類
Java 語言中,非靜態(tài)內(nèi)部類的主要作用有兩個:
當(dāng)內(nèi)部類只在外部類中使用時,匿名內(nèi)部類可以讓外部不知道它的存在,從而減少了代碼的維護(hù)工作。
當(dāng)內(nèi)部類持有外部類時,它就可以直接使用外部類中的變量了,這樣可以很方便的完成調(diào)用,如下代碼所示:
但是,靜態(tài)內(nèi)部類就無法持有外部類和其非靜態(tài)字段了。
比如下邊這樣就會報錯
報錯:
實例:持有外部類
「代碼」
「斷點調(diào)試」
可以看到:內(nèi)部類持有外部類的對象的引用,是以“this$0”這個字段來保存的。
實例:不持有外部類
「代碼」
「斷點調(diào)試」
可以發(fā)現(xiàn):內(nèi)部類不再持有外部類了。
實例:內(nèi)存泄露
「簡介」
若內(nèi)部類持有外部類的引用,對內(nèi)部類的使用很多時,會導(dǎo)致外部類數(shù)目很多。此時,就算是外部類的數(shù)據(jù)沒有被用到,外部類的數(shù)據(jù)所占空間也不會被釋放。 本處在外部類存放大量的數(shù)據(jù)來模擬。
「代碼」
「測試」
可以看到:運行了八千多次的時候就內(nèi)存溢出了。
我換了一臺 mac 電腦,4000 多就內(nèi)存溢出了。
不會內(nèi)存泄露的方案
「簡介」
內(nèi)部類改為靜態(tài)的之后,它所引用的對象或?qū)傩砸脖仨毷庆o態(tài)的,所以靜態(tài)內(nèi)部類無法獲得外部對象的引用,只能從 JVM 的 Method Area(方法區(qū))獲取到 static 類型的引用。
「代碼」
「測試」
可以發(fā)現(xiàn):循環(huán)了四十多萬次都沒有內(nèi)存溢出。
審核編輯:劉清
-
JAVA語言
+關(guān)注
關(guān)注
0文章
138瀏覽量
20095 -
JVM
+關(guān)注
關(guān)注
0文章
158瀏覽量
12228
原文標(biāo)題:Java 內(nèi)部類有坑。。100 % 內(nèi)存泄露!
文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論