簡(jiǎn)介
為什么要持有外部類(lèi)
實(shí)例:持有外部類(lèi)
實(shí)例:不持有外部類(lèi)
實(shí)例:內(nèi)存泄露
不會(huì)內(nèi)存泄露的方案
簡(jiǎn)介
「說(shuō)明」
本文介紹 Java 內(nèi)部類(lèi)持有外部類(lèi)導(dǎo)致內(nèi)存泄露的原因以及其解決方案。
「為什么內(nèi)部類(lèi)持有外部類(lèi)會(huì)導(dǎo)致內(nèi)存泄露?」
非靜態(tài)內(nèi)部類(lèi)會(huì)持有外部類(lèi),如果有地方引用了這個(gè)非靜態(tài)內(nèi)部類(lèi),會(huì)導(dǎo)致外部類(lèi)也被引用,垃圾回收時(shí)無(wú)法回收這個(gè)外部類(lèi)(即使外部類(lèi)已經(jīng)沒(méi)有其他地方在使用了)。
「解決方案」
不要讓其他的地方持有這個(gè)非靜態(tài)內(nèi)部類(lèi)的引用,直接在這個(gè)非靜態(tài)內(nèi)部類(lèi)執(zhí)行業(yè)務(wù)。
將非靜態(tài)內(nèi)部類(lèi)改為靜態(tài)內(nèi)部類(lèi)。內(nèi)部類(lèi)改為靜態(tài)的之后,它所引用的對(duì)象或?qū)傩砸脖仨毷庆o態(tài)的,所以靜態(tài)內(nèi)部類(lèi)無(wú)法獲得外部對(duì)象的引用,只能從 JVM 的 Method Area(方法區(qū))獲取到static類(lèi)型的引用。
基于 Spring Boot + MyBatis Plus + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶(hù)小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶(hù)、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
項(xiàng)目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
視頻教程:https://doc.iocoder.cn/video/
為什么要持有外部類(lèi)
Java 語(yǔ)言中,非靜態(tài)內(nèi)部類(lèi)的主要作用有兩個(gè):
當(dāng)內(nèi)部類(lèi)只在外部類(lèi)中使用時(shí),匿名內(nèi)部類(lèi)可以讓外部不知道它的存在,從而減少了代碼的維護(hù)工作。
當(dāng)內(nèi)部類(lèi)持有外部類(lèi)時(shí),它就可以直接使用外部類(lèi)中的變量了,這樣可以很方便的完成調(diào)用,如下代碼所示:
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)內(nèi)部類(lèi)就無(wú)法持有外部類(lèi)和其非靜態(tài)字段了。比如下邊這樣就會(huì)報(bào)錯(cuò)
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); } }
報(bào)錯(cuò):
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶(hù)小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶(hù)、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能
項(xiàng)目地址:https://gitee.com/zhijiantianya/yudao-cloud
視頻教程:https://doc.iocoder.cn/video/
實(shí)例:持有外部類(lèi)
「代碼」
packageorg.example.a; classOuter{ classInner{ } InnercreateInner(){ returnnewInner(); } } publicclassDemo{ publicstaticvoidmain(String[]args){ Outer.Innerinner=newOuter().createInner(); System.out.println(inner); } }
「斷點(diǎn)調(diào)試」
可以看到:內(nèi)部類(lèi)持有外部類(lèi)的對(duì)象的引用,是以“this$0”這個(gè)字段來(lái)保存的。
實(shí)例:不持有外部類(lèi)
「代碼」
packageorg.example.a; classOuter{ staticclassInner{ } InnercreateInner(){ returnnewInner(); } } publicclassDemo{ publicstaticvoidmain(String[]args){ Outer.Innerinner=newOuter().createInner(); System.out.println(inner); } }
「斷點(diǎn)調(diào)試」
可以發(fā)現(xiàn):內(nèi)部類(lèi)不再持有外部類(lèi)了。
實(shí)例:內(nèi)存泄露
「簡(jiǎn)介」
若內(nèi)部類(lèi)持有外部類(lèi)的引用,對(duì)內(nèi)部類(lèi)的使用很多時(shí),會(huì)導(dǎo)致外部類(lèi)數(shù)目很多。此時(shí),就算是外部類(lèi)的數(shù)據(jù)沒(méi)有被用到,外部類(lèi)的數(shù)據(jù)所占空間也不會(huì)被釋放。
本處在外部類(lèi)存放大量的數(shù)據(jù)來(lái)模擬。
「代碼」
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
「測(cè)試」
可以看到:運(yùn)行了八千多次的時(shí)候就內(nèi)存溢出了。
換了一臺(tái) mac 電腦,4000 多就內(nèi)存溢出了。
不會(huì)內(nèi)存泄露的方案
「簡(jiǎn)介」
內(nèi)部類(lèi)改為靜態(tài)的之后,它所引用的對(duì)象或?qū)傩砸脖仨毷庆o態(tài)的,所以靜態(tài)內(nèi)部類(lèi)無(wú)法獲得外部對(duì)象的引用,只能從 JVM 的 Method Area(方法區(qū))獲取到 static 類(lèi)型的引用。
「代碼」
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
「測(cè)試」
可以發(fā)現(xiàn):循環(huán)了四十多萬(wàn)次都沒(méi)有內(nèi)存溢出。
以上,希望能對(duì)大家在使用內(nèi)部類(lèi)時(shí)會(huì)有所幫助。
-
內(nèi)存
+關(guān)注
關(guān)注
8文章
3052瀏覽量
74214 -
JAVA
+關(guān)注
關(guān)注
19文章
2974瀏覽量
104968 -
JVM
+關(guān)注
關(guān)注
0文章
158瀏覽量
12252 -
static
+關(guān)注
關(guān)注
0文章
33瀏覽量
10396
原文標(biāo)題:Java內(nèi)部類(lèi)有坑,100%內(nèi)存泄露!
文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論