簡介
為什么要持有外部類
實例:持有外部類
實例:不持有外部類
實例:內存泄露
不會內存泄露的方案
簡介
「說明」
本文介紹 Java 內部類持有外部類導致內存泄露的原因以及其解決方案。
「為什么內部類持有外部類會導致內存泄露?」
非靜態(tài)內部類會持有外部類,如果有地方引用了這個非靜態(tài)內部類,會導致外部類也被引用,垃圾回收時無法回收這個外部類(即使外部類已經(jīng)沒有其他地方在使用了)。
「解決方案」
不要讓其他的地方持有這個非靜態(tài)內部類的引用,直接在這個非靜態(tài)內部類執(zhí)行業(yè)務。
將非靜態(tài)內部類改為靜態(tài)內部類。內部類改為靜態(tài)的之后,它所引用的對象或屬性也必須是靜態(tài)的,所以靜態(tài)內部類無法獲得外部對象的引用,只能從 JVM 的 Method Area(方法區(qū))獲取到static類型的引用。
基于 Spring Boot + MyBatis Plus + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權限、多租戶、數(shù)據(jù)權限、工作流、三方登錄、支付、短信、商城等功能
項目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
視頻教程:https://doc.iocoder.cn/video/
為什么要持有外部類
Java 語言中,非靜態(tài)內部類的主要作用有兩個:
當內部類只在外部類中使用時,匿名內部類可以讓外部不知道它的存在,從而減少了代碼的維護工作。
當內部類持有外部類時,它就可以直接使用外部類中的變量了,這樣可以很方便的完成調用,如下代碼所示:
packageorg.example.a; classOuter{ privateStringouterName="Tony"; classInner{ privateStringname; publicInner(){ this.name=outerName; } } InnercreateInner(){ returnnewInner(); } } publicclassDemo{ publicstaticvoidmain(String[]args){ Outer.Innerinner=newOuter().createInner(); System.out.println(inner); } }
但是,靜態(tài)內部類就無法持有外部類和其非靜態(tài)字段了。比如下邊這樣就會報錯
packageorg.example.a; classOuter{ privateStringouterName="Tony"; staticclassInner{ privateStringname; publicInner(){ this.name=outerName; } } InnercreateInner(){ returnnewInner(); } } publicclassDemo{ publicstaticvoidmain(String[]args){ Outer.Innerinner=newOuter().createInner(); System.out.println(inner); } }
報錯:
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實現(xiàn)的后臺管理系統(tǒng) + 用戶小程序,支持 RBAC 動態(tài)權限、多租戶、數(shù)據(jù)權限、工作流、三方登錄、支付、短信、商城等功能
項目地址:https://gitee.com/zhijiantianya/yudao-cloud
視頻教程:https://doc.iocoder.cn/video/
實例:持有外部類
「代碼」
packageorg.example.a; classOuter{ classInner{ } InnercreateInner(){ returnnewInner(); } } publicclassDemo{ publicstaticvoidmain(String[]args){ Outer.Innerinner=newOuter().createInner(); System.out.println(inner); } }
「斷點調試」
可以看到:內部類持有外部類的對象的引用,是以“this$0”這個字段來保存的。
實例:不持有外部類
「代碼」
packageorg.example.a; classOuter{ staticclassInner{ } InnercreateInner(){ returnnewInner(); } } publicclassDemo{ publicstaticvoidmain(String[]args){ Outer.Innerinner=newOuter().createInner(); System.out.println(inner); } }
「斷點調試」
可以發(fā)現(xiàn):內部類不再持有外部類了。
實例:內存泄露
「簡介」
若內部類持有外部類的引用,對內部類的使用很多時,會導致外部類數(shù)目很多。此時,就算是外部類的數(shù)據(jù)沒有被用到,外部類的數(shù)據(jù)所占空間也不會被釋放。
本處在外部類存放大量的數(shù)據(jù)來模擬。
「代碼」
packageorg.example.a; importjava.util.ArrayList; importjava.util.List; classOuter{ privateint[]data; publicOuter(intsize){ this.data=newint[size]; } classInnner{ } InnnercreateInner(){ returnnewInnner(); } } publicclassDemo{ publicstaticvoidmain(String[]args){ List
「測試」
可以看到:運行了八千多次的時候就內存溢出了。
換了一臺 mac 電腦,4000 多就內存溢出了。
不會內存泄露的方案
「簡介」
內部類改為靜態(tài)的之后,它所引用的對象或屬性也必須是靜態(tài)的,所以靜態(tài)內部類無法獲得外部對象的引用,只能從 JVM 的 Method Area(方法區(qū))獲取到 static 類型的引用。
「代碼」
packageorg.example.a; importjava.util.ArrayList; importjava.util.List; classOuter{ privateint[]data; publicOuter(intsize){ this.data=newint[size]; } staticclassInner{ } InnercreateInner(){ returnnewInner(); } } publicclassDemo{ publicstaticvoidmain(String[]args){ List
「測試」
可以發(fā)現(xiàn):循環(huán)了四十多萬次都沒有內存溢出。
以上,希望能對大家在使用內部類時會有所幫助。
-
內存
+關注
關注
8文章
3063瀏覽量
74374 -
JAVA
+關注
關注
19文章
2976瀏覽量
105211 -
JVM
+關注
關注
0文章
158瀏覽量
12270 -
static
+關注
關注
0文章
33瀏覽量
10413
原文標題:Java內部類有坑,100%內存泄露!
文章出處:【微信號:芋道源碼,微信公眾號:芋道源碼】歡迎添加關注!文章轉載請注明出處。
發(fā)布評論請先 登錄
相關推薦
![](https://file1.elecfans.com/web2/M00/85/B6/wKgaomRmO5mAAESCAAB-QzGYzOY950.png)
![](https://file1.elecfans.com/web2/M00/85/BC/wKgZomRmPJ-AC97kAAByeLPU10I474.png)
java rules下載/java規(guī)范中文版
java基礎知識精講視頻教程百度云盤分享!
ARM之靜態(tài)變量簡析
對在Firefly-RK3288開發(fā)板上的Hello進行內存泄漏分析常見實例
接口、內部類和Java API基礎
java內部類分析詳解
java內部類怎么寫
![<b class='flag-5'>java</b><b class='flag-5'>內部類</b>怎么寫](https://file.elecfans.com/web2/M00/49/E1/pYYBAGKhvG-AULSWAAA0_IiBCBU808.png)
評論