<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java內(nèi)部類有坑,100%內(nèi)存泄露!

          共 6661字,需瀏覽 14分鐘

           ·

          2022-10-14 21:22

          推薦閱讀:推薦一款搜索開源代碼的神器 :Kooder!
          今天給大家分享一種,Java內(nèi)部類使用不當導(dǎo)致的內(nèi)存泄露問題,最終導(dǎo)致內(nèi)存溢出!希望能夠幫助到大家!

          簡介

          「說明」

          本文介紹 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)沒有其他地方在使用了)。

          「解決方案」

          1. 不要讓其他的地方持有這個非靜態(tài)內(nèi)部類的引用,直接在這個非靜態(tài)內(nèi)部類執(zhí)行業(yè)務(wù)。
          2. 將非靜態(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)部類的主要作用有兩個:

          1. 當內(nèi)部類只在外部類中使用時,匿名內(nèi)部類可以讓外部不知道它的存在,從而減少了代碼的維護工作。
          2. 當內(nèi)部類持有外部類時,它就可以直接使用外部類中的變量了,這樣可以很方便的完成調(diào)用,如下代碼所示:
          package org.example.a;

          class Outer{
              private String outerName = "Tony";

              class Inner{
                  private String name;

                  public Inner() {
                      this.name = outerName;
                  }
              }

              Inner createInner() {
                  return new Inner();
              }
          }

          public class Demo {
              public static void main(String[] args) {
                  Outer.Inner inner = new Outer().createInner();
                  System.out.println(inner);
              }
          }

          但是,靜態(tài)內(nèi)部類就無法持有外部類和其非靜態(tài)字段了。比如下邊這樣就會報錯

          package org.example.a;

          class Outer{
              private String outerName = "Tony";

              static class Inner{
                  private String name;

                  public Inner() {
                      this.name = outerName;
                  }
              }

              Inner createInner() {
                  return new Inner();
              }
          }

          public class Demo {
              public static void main(String[] args) {
                  Outer.Inner inner = new Outer().createInner();
                  System.out.println(inner);
              }
          }

          報錯:

          實例:持有外部類

          「代碼」

          package org.example.a;

          class Outer{
              class Inner {

              }

              Inner createInner() {
                  return new Inner();
              }
          }

          public class Demo {
              public static void main(String[] args) {
                  Outer.Inner inner = new Outer().createInner();
                  System.out.println(inner);
              }
          }

          「斷點調(diào)試」

          可以看到:內(nèi)部類持有外部類的對象的引用,是以“this$0”這個字段來保存的。

          實例:不持有外部類

          「代碼」

          package org.example.a;

          class Outer{
              static class Inner {

              }

              Inner createInner() {
                  return new Inner();
              }
          }

          public class Demo {
              public static void main(String[] args) {
                  Outer.Inner inner = new Outer().createInner();
                  System.out.println(inner);
              }
          }

          「斷點調(diào)試」

          可以發(fā)現(xiàn):內(nèi)部類不再持有外部類了。

          實例:內(nèi)存泄露

          「簡介」

          若內(nèi)部類持有外部類的引用,對內(nèi)部類的使用很多時,會導(dǎo)致外部類數(shù)目很多。此時,就算是外部類的數(shù)據(jù)沒有被用到,外部類的數(shù)據(jù)所占空間也不會被釋放。

          本處在外部類存放大量的數(shù)據(jù)來模擬。

          「代碼」

          package org.example.a;

          import java.util.ArrayList;
          import java.util.List;

          class Outer{
              private int[] data;

              public Outer(int size) {
                  this.data = new int[size];
              }

              class Innner{

              }

              Innner createInner() {
                  return new Innner();
              }
          }

          public class Demo {
              public static void main(String[] args) {
                  List<Object> list = new ArrayList<>();
                  int counter = 0;
                  while (true) {
                      list.add(new Outer(100000).createInner());
                      System.out.println(counter++);
                  }
              }
          }

          「測試」

          可以看到:運行了八千多次的時候就內(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 類型的引用。

          「代碼」

          package org.example.a;

          import java.util.ArrayList;
          import java.util.List;

          class Outer{
              private int[] data;

              public Outer(int size) {
                  this.data = new int[size];
              }

              static class Inner {

              }

              Inner createInner() {
                  return new Inner();
              }
          }

          public class Demo {
              public static void main(String[] args) {
                  List<Object> list = new ArrayList<>();
                  int counter = 0;
                  while (true) {
                      list.add(new Outer(100000).createInner());
                      System.out.println(counter++);
                  }
              }
          }

          「測試」

          可以發(fā)現(xiàn):循環(huán)了四十多萬次都沒有內(nèi)存溢出。

          以上,希望能對大家在使用內(nèi)部類時會有所幫助。

          瀏覽 26
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  性高潮视频在线观看 | 欧美成人自拍 | 最好看2019中文在线播放电影 | 日本精品18禁 | 欧美成人性网 |