欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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ì),希望對大家有所幫助

簡介

說明

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

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

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

為什么要持有外部類

Java 語言中,非靜態(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對象)

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è)對 Test 的引用被存入到 this$0 中,也就是說這個(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))

可見:它是持有外部類Test的對象的。

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

class org.example.a.Test

什么時(shí)候會內(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類里邊有比較大的對象,而這些大對象根本沒被用到,則會內(nèi)存泄露。

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

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

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

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)部類不會持有外部類的對象的引用。

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

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

代碼

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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot調(diào)用第三方WebService接口的兩種方法

    SpringBoot調(diào)用第三方WebService接口的兩種方法

    本文主要介紹了SpringBoot調(diào)用第三方WebService接口的兩種方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • java的jps命令使用詳解

    java的jps命令使用詳解

    這篇文章介紹了java的jps命令使用詳解,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • 詳解Java MyBatis 插入數(shù)據(jù)庫返回主鍵

    詳解Java MyBatis 插入數(shù)據(jù)庫返回主鍵

    這篇文章主要介紹了詳解Java MyBatis 插入數(shù)據(jù)庫返回主鍵,有興趣的可以了解一下。
    2017-01-01
  • IntelliJ?IDEA?2020.2?全家桶及以下版本激活工具大全【喜訊】

    IntelliJ?IDEA?2020.2?全家桶及以下版本激活工具大全【喜訊】

    這篇文章主要介紹了IntelliJ?IDEA?2020.2?全家桶及以下版本激活工具大全【喜訊】,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • SpringBoot2使用WebFlux函數(shù)式編程的方法

    SpringBoot2使用WebFlux函數(shù)式編程的方法

    這篇文章主要介紹了SpringBoot2使用WebFlux函數(shù)式編程的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-08-08
  • spring四種依賴注入方式的詳細(xì)介紹

    spring四種依賴注入方式的詳細(xì)介紹

    本篇文章主要介紹了spring四種依賴注入方式的詳細(xì)介紹,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-02-02
  • 關(guān)于mybatis傳入?yún)?shù)一直為null的問題

    關(guān)于mybatis傳入?yún)?shù)一直為null的問題

    這篇文章主要介紹了關(guān)于mybatis傳入?yún)?shù)一直為null的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • Mysql中的聚簇索引cluster index解析

    Mysql中的聚簇索引cluster index解析

    這篇文章主要介紹了Mysql中的聚簇索引cluster index解析,聚簇索引是一種數(shù)據(jù)庫索引的類型,它將數(shù)據(jù)行物理上存儲在磁盤上按照索引的順序進(jìn)行排序,聚簇索引可以提高查詢性能,因?yàn)樗梢詼p少磁盤I/O操作,需要的朋友可以參考下
    2023-10-10
  • Windows下如何安裝配置Redis環(huán)境

    Windows下如何安裝配置Redis環(huán)境

    這篇文章主要介紹了Windows下如何安裝配置Redis環(huán)境,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12
  • 快速理解Java垃圾回收和jvm中的stw

    快速理解Java垃圾回收和jvm中的stw

    這篇文章主要介紹了快速理解Java垃圾回收和jvm中的stw,涉及Java代碼的停頓,jvm中的線程等相關(guān)內(nèi)容,還是十分不錯(cuò)的,需要的朋友可以參考。
    2017-10-10

最新評論