最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java匿名內(nèi)部類導(dǎo)致內(nèi)存泄露的原因與解決方案詳解

 更新時(shí)間:2022年11月23日 11:30:38   作者:IT利刃出鞘  
這篇文章主要為大家詳細(xì)介紹了Java因?yàn)槟涿麅?nèi)部類導(dǎo)致內(nèi)存泄露的原因以及其解決方案,文中的示例代碼講解詳細(xì),希望對(duì)大家有所幫助

簡(jiǎn)介

說(shuō)明

本文用示例介紹匿名內(nèi)部類會(huì)導(dǎo)致內(nèi)存泄漏的原因及其解決方案。

相關(guān)網(wǎng)址

普通內(nèi)部類的內(nèi)存泄露:Java內(nèi)部類持有外部類導(dǎo)致內(nèi)存泄露--原因/解決方案

為什么要持有外部類

Java 語(yǔ)言中,非靜態(tài)內(nèi)部類的主要作用有兩個(gè):

當(dāng)匿名內(nèi)部類只在外部類(主類)中使用時(shí),匿名內(nèi)部類可以讓外部不知道它的存在,從而減少了代碼的維護(hù)工作。

當(dāng)匿名內(nèi)部類持有外部類時(shí),它就可以直接使用外部類中的變量了,這樣可以很方便的完成調(diào)用,如下代碼所示:

package org.example.a;
 
import java.util.ArrayList;
import java.util.List;
 
public class Demo {
    private static String name = "Tony";
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>() {{
            add("a");
            add("b");
            add(name);
        }};
        System.out.println(list);
    }
}

實(shí)例:持有外部類

代碼

package org.example.a;
 
import java.util.ArrayList;
import java.util.List;
 
class Test{
    public List<String> createList() {
        List<String> list = new ArrayList<String>() {{
            add("a");
            add("b");
        }};
        return list;
    }
}
 
public class Demo {
    public static void main(String[] args) {
        System.out.println(new Test().createList());
    }
}

編譯查看class

命令:javac Demo.java

結(jié)果:

Idea查看Test$1.class(可以發(fā)現(xiàn):持有了一個(gè)外部類Test對(duì)象)

package org.example.a;
 
import java.util.ArrayList;
 
class Test$1 extends ArrayList<String> {
    Test$1(Test var1) {
        this.this$0 = var1;
        this.add("a");
        this.add("b");
    }
}

Idea查看Test.class

package org.example.a;
 
import java.util.ArrayList;
import java.util.List;
 
class Test {
    Test() {
    }
 
    public List<String> createList() {
        ArrayList var1 = new ArrayList<String>() {
            {
                this.add("a");
                this.add("b");
            }
        };
        return var1;
    }
}

Idea查看Demo.class

package org.example.a;
 
public class Demo {
    public Demo() {
    }
 
    public static void main(String[] var0) {
        System.out.println((new Test()).createList());
    }
}

查看字節(jié)碼

命令

javap -c Test$1.class

結(jié)果

Compiled from "Demo.java"
class org.example.a.Test$1 extends java.util.ArrayList<java.lang.String> {
  final org.example.a.Test this$0;
 
  org.example.a.Test$1(org.example.a.Test);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #1                  // Field this$0:Lorg/example/a/Test;
       5: aload_0
       6: invokespecial #2                  // Method java/util/ArrayList."<init>":()V
       9: aload_0
      10: ldc           #3                  // String a
      12: invokevirtual #4                  // Method add:(Ljava/lang/Object;)Z
      15: pop
      16: aload_0
      17: ldc           #5                  // String b
      19: invokevirtual #4                  // Method add:(Ljava/lang/Object;)Z
      22: pop
      23: return
}

分析

關(guān)鍵代碼的在 putfield 這一行,此行表示有一個(gè)對(duì) Test 的引用被存入到 this$0 中,也就是說(shuō)這個(gè)匿名內(nèi)部類持有了外部類的引用。 

代碼驗(yàn)證

package org.example.a;
 
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
 
class Test{
    public List<String> createList() {
        List<String> list = new ArrayList<String>() {{
            add("a");
            add("b");
        }};
        return list;
    }
}
 
public class Demo {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        List<String> list = new Test().createList();
        // 獲取一個(gè)類的所有字段
        Field field = list.getClass().getDeclaredField("this$0");
        // 設(shè)置允許方法私有的 private 修飾的變量
        field.setAccessible(true);
        System.out.println(field.get(list).getClass());
    }
}

打個(gè)斷點(diǎn)(注意:我這里是用Object模式(右鍵Variables里的this=> View as=> Object))

可見(jiàn):它是持有外部類Test的對(duì)象的。

執(zhí)行結(jié)果:

class org.example.a.Test

什么時(shí)候會(huì)內(nèi)存泄露

非靜態(tài)方法返回匿名內(nèi)部類的引用可能導(dǎo)致內(nèi)存泄露,例:

?class Test{
    public List<String> createList() {
        List<String> list = new ArrayList<String>() {{
            add("a");
            add("b");
        }};
        return list;
    }
}

跟上邊“普通內(nèi)部類” 一樣,若Test類里邊有比較大的對(duì)象,而這些大對(duì)象根本沒(méi)被用到,則會(huì)內(nèi)存泄露。

不會(huì)內(nèi)存泄漏的方案

方案1:不返回內(nèi)部類對(duì)象引用

業(yè)務(wù)直接處理,不返回內(nèi)部類對(duì)象引用

class Test{
    public void createList() {
        List<String> list = new ArrayList<String>() {{
            add("a");
            add("b");
        }};
        System.out.println(list);
    }
}

方案2:匿名內(nèi)部類改為靜態(tài)的

將匿名內(nèi)部類改為靜態(tài)的。此時(shí),內(nèi)部類不會(huì)持有外部類的對(duì)象的引用。

為什么這樣就不會(huì)內(nèi)存泄露了?

因?yàn)槟涿麅?nèi)部類是靜態(tài)的之后,它所引用的對(duì)象或?qū)傩砸脖仨毷庆o態(tài)的了,因此就可以直接從 JVM 的 Method Area(方法區(qū))獲取到引用而無(wú)需持久外部對(duì)象了。

代碼

package org.example.a;
 
import java.util.ArrayList;
import java.util.List;
 
class Test{
    public static List<String> createList() {
        List<String> list = new ArrayList<String>() {{
            add("a");
            add("b");
        }};
        return list;
    }
}
 
public class Demo {
    public static void main(String[] args) {
        System.out.println(Test.createList());
    }
}

執(zhí)行結(jié)果

[a, b]

編譯

命令:javac Demo.java

結(jié)果

Idea查看Test$1.class

package org.example.a;
 
import java.util.ArrayList;
 
final class Test$1 extends ArrayList<String> {
    Test$1() {
        this.add("a");
        this.add("b");
    }
}

到此這篇關(guān)于Java匿名內(nèi)部類導(dǎo)致內(nèi)存泄露的原因與解決方案詳解的文章就介紹到這了,更多相關(guān)Java內(nèi)存泄露內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java讀取解析xml文件實(shí)例

    java讀取解析xml文件實(shí)例

    這篇文章主要介紹了java讀取解析xml文件實(shí)例,本文創(chuàng)建了一個(gè)XML解析類同時(shí)講解了循環(huán)節(jié)點(diǎn)輸出方式,需要的朋友可以參考下
    2015-03-03
  • Spring MVC登錄注冊(cè)以及轉(zhuǎn)換json數(shù)據(jù)

    Spring MVC登錄注冊(cè)以及轉(zhuǎn)換json數(shù)據(jù)

    本文主要介紹了Spring MVC登錄注冊(cè)以及轉(zhuǎn)換json數(shù)據(jù)的相關(guān)知識(shí)。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧
    2017-04-04
  • Java JDK 動(dòng)態(tài)代理的使用方法示例

    Java JDK 動(dòng)態(tài)代理的使用方法示例

    Java 動(dòng)態(tài)代理機(jī)制以巧妙的方式近乎完美地實(shí)踐了代理模式的設(shè)計(jì)理念。下面這篇文章主要給大家分享了關(guān)于Java JDK 動(dòng)態(tài)代理的使用方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-07-07
  • Java處理科學(xué)計(jì)數(shù)法數(shù)字方式

    Java處理科學(xué)計(jì)數(shù)法數(shù)字方式

    這篇文章主要介紹了Java處理科學(xué)計(jì)數(shù)法數(shù)字方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • SpringBoot集成quartz實(shí)現(xiàn)定時(shí)任務(wù)

    SpringBoot集成quartz實(shí)現(xiàn)定時(shí)任務(wù)

    這篇文章主要介紹了如何使用SpringBoot整合Quartz,并將定時(shí)任務(wù)寫入庫(kù)中(持久化存儲(chǔ)),還可以任意對(duì)定時(shí)任務(wù)進(jìn)行如刪除、暫停、恢復(fù)等操作,需要的可以了解下
    2023-09-09
  • Spring Cloud Sleuth整合zipkin過(guò)程解析

    Spring Cloud Sleuth整合zipkin過(guò)程解析

    這篇文章主要介紹了Spring Cloud Sleuth整合zipkin過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • Mybatis通過(guò)Spring完成代理類注入的流程分析

    Mybatis通過(guò)Spring完成代理類注入的流程分析

    這篇文章主要介紹了Mybatis通過(guò)Spring完成代理類注入的流程分析,本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • JDBC PreparedStatement Like參數(shù)報(bào)錯(cuò)解決方案

    JDBC PreparedStatement Like參數(shù)報(bào)錯(cuò)解決方案

    這篇文章主要介紹了JDBC PreparedStatement Like參數(shù)報(bào)錯(cuò)解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • SpringBoot單點(diǎn)登錄實(shí)現(xiàn)過(guò)程詳細(xì)分析

    SpringBoot單點(diǎn)登錄實(shí)現(xiàn)過(guò)程詳細(xì)分析

    這篇文章主要介紹了SpringBoot單點(diǎn)登錄實(shí)現(xiàn)過(guò)程,單點(diǎn)登錄英文全稱Single?Sign?On,簡(jiǎn)稱就是SSO。它的解釋是:在多個(gè)應(yīng)用系統(tǒng)中,只需要登錄一次,就可以訪問(wèn)其他相互信任的應(yīng)用系統(tǒng)
    2022-12-12
  • java多線程創(chuàng)建及線程安全詳解

    java多線程創(chuàng)建及線程安全詳解

    多線程是日常開(kāi)發(fā)中的常用知識(shí),也是難用知識(shí)。通這篇文章主要給大家介紹了關(guān)于java多線程創(chuàng)建及線程安全的相關(guān)資料,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05

最新評(píng)論

镇平县| 安塞县| 新乡市| 香港| 西平县| 水富县| 巴马| 裕民县| 杨浦区| 易门县| 西吉县| 绍兴市| 方正县| 承德市| 珲春市| 色达县| 尚义县| 阿鲁科尔沁旗| 永顺县| 邵阳市| 林芝县| 芷江| 宜兰市| 陆良县| 怀化市| 芦山县| 武城县| 星子县| 高邑县| 巴楚县| 尉犁县| 宜宾市| 磴口县| 紫阳县| 邛崃市| 旺苍县| 磐安县| 乌兰县| 蒙自县| 浮山县| 峡江县|