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

Java中的HashMap內存泄漏問題詳解

 更新時間:2023年09月07日 10:19:34   作者:唐宋xy  
這篇文章主要介紹了Java中的HashMap內存泄漏問題詳解,WeakHashMap中的key是弱引用,如果再使用之后沒有及時remove掉這個key,那么當GC時key就可能會被回收,導致key對應的value對象占用的內存無法回收進而導致內存泄漏,需要的朋友可以參考下

前言

眾所周知, WeakHashMap 中的 key 是弱引用,如果再使用之后沒有及時 remove 掉這個key,那么當GC時key就可能會被回收,導致key對應的value對象占用的內存無法回收進而導致內存泄漏,如果有大量的key可能會導致內存溢出、頻繁FullGC等問題。

說了這么多導致內存泄漏是因為 WeakHashMap 的 key 是弱引用從而導致內存泄漏,但是 HashMap 的key是強引用,也會導致內存泄漏嗎?

Java中的四種引用

先簡單了解一下Java中的四種引用分別是什么

強引用

如果一個對象是強引用, GC 不會回收該對象(在該對象可達時),就算發(fā)生內存溢出也不會回收該對象。一般手動 new 出來的對象都是強引用

什么時候回收強引用對象呢?平常寫代碼中那么多 new 的對象怎么沒有發(fā)生內存溢出呢

平常代碼中有大量的例如:Objedt obj = new Object() 這種手動創(chuàng)建的對象既然都是強引用,不會被回收,JVM還不是分分鐘爆炸?

其實,強引用對象也是會被回收的,根據GC回收的算法—可達性分析算法進行判斷,當一個對象不可達時就會被回收(不可達就不繼續(xù)展開啦),或者手動將 obj=null ,也會回收該對象。因為obj指向這個 new 出來的對象,所以是可達的對象不會被回收,但是 obj 一般是在棧中,當前線程執(zhí)行完成,該方法棧就會被回收,所以obj也會被回收,進而導致堆中該對象沒有引用可達而被回收。

軟引用

如果堆內存空間充足,則一般GC時不會回收軟引用對象,只有在堆內存空間不足的時候才會回收軟引用內存空間的對象。使用場景:(和弱引用相同的作用)一般可以用作本地緩存,防止緩存中的數據量太大導致內存溢出

弱引用

無論堆內存空間是否充足,在每次GC的時候都可能會對弱引用對象進行回收。

虛引用

虛引用,正如其名,對一個對象而言,這個引用形同虛設,有和沒有一樣,簡單來說虛引用就相當于沒有引用。它的作用就是在GC的時候會發(fā)出一個系統(tǒng)通知

HashMap內存泄漏場景

HashMap的 put 方法分析

先分析一下HashMap的put/get

HashMap 的 put 方法在保存數據的時候會根據** key 計算出來hash值**,然后根據hash值獲取到數組的下標的位置,沒有發(fā)生hash沖突就只直接保存,如果發(fā)生hash沖突則形成鏈表。

get 方法是根據key的hash值得到數組的下標,然后直接獲取或者遍歷鏈表并調用 equals 方法來獲取數據。

第一種:內存泄漏代碼

下面的代碼會導致內存泄漏嗎

class Person {
  String name;
  int age;
  //省略getter/setter方法
  ...
}
HashMap<Person, Integer> map = new HashMap<>();
Person gay = new Person("gay倫", 18);
Person yase = new Person("亞瑟", 10);
Person timo = new Person("提莫", 11);
// 保存
map.put(gay, 1);
map.put(yase, 2);
map.put(timo, 3);
// 第一次獲取
Integer x = map.get(gay);
System.out.println(x);
Integer y = map.get(new Person("gay倫", 18));
System.out.println(y); // 這里可以直接獲取到對象嗎?

控制臺輸出:

null

原因分析

相信注重細節(jié)的小伙伴已經看出來了,為什么第二次沒有獲取到對應的 value 呢,這是因為 Person 沒有重寫** hashcode 和 equals ,導致默認的計算的 hashcode 不同,所以無法獲取到第一次保存的 value (還記得上面的前戲**嗎?前戲是非常重要的)

簡單說就是兩次計算的 hashcode 和 equals 不同導致HashMap的 get 方法無法獲取到對應的 value

如果 HashMap 一直沒有回收(例如定義為常量、靜態(tài)變量),那么無法 remove 對應的key,就會導致value一直被HashMap引用,從而導致占用的內存無法回收,導致內存泄漏。

解決方案

解決方案:如果是自定義的類,最好重寫 hashcode 和 equals ,如果是保存到Map中,則一定要重寫 hashcode 和 equals

修正代碼示例

使用IDEA自動生成的hashcode和equals

...
// 加上equals和hashcode =》 IDEA自動生成
@Override
public boolean equals(Object o) {
  if (this == o) return true;
  if (o == null || getClass() != o.getClass()) return false;
  Person person = (Person) o;
  return age == person.age &&
  Objects.equals(name, person.name);
}
@Override
public int hashCode() {
	return Objects.hash(name, age);
}
...

控制臺輸出:

11

第二種:內存泄漏代碼

看看下面的代碼是否會導致內存泄漏

class Person {
  String name;
  int age;
  //省略getter/setter方法
  ...
  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Person person = (Person) o;
    return age == person.age &&
    Objects.equals(name, person.name);
  }
  @Override
  public int hashCode() {
    return Objects.hash(name, age);
  }
}
HashMap<Person, Integer> map = new HashMap<>();
Person gay = new Person("gay倫", 18);
Person yase = new Person("亞瑟", 10);
Person timo = new Person("提莫", 11);
// 保存
map.put(gay, 1);
map.put(yase, 2);
map.put(timo, 3);
// 第一次獲取
Integer x = map.get(gay);
System.out.println(x);
// 修改對象的name屬性
gay.setName("蓋倫");
// 第二次獲取
Integer y = map.get(gay);
System.out.println(y); // 這里可以獲取到對象嗎?

控制臺輸出:

null

原因分析

怎么就改一下 name 就獲取不到了?(其實還是要看前戲)看見上面的 hashcode 和 equals 了沒有, key 的 hashcode 是通過 Objects.hash(name, age); 計算的,hash值和 name 和 age 有關的,如果其中一個改變了,那么計算出來的 hash 值就不同,計算出來的下標可能就不同,所以就獲取不到 value

解決方案

在重寫 hashcode 和 equals 方法的時候,一定要注意參與計算的相關字段,最好不要更改參與計算的字段屬性值,如果可以的話,可以將參與計算的字段定義為 final 類型

修正代碼演示

class Person {
  String name;
  // 定義為final
  final int age;
  //省略getter/setter方法
  ...
  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Person person = (Person) o;
    // 只判斷name相同即可
    return age == person.age;
  }
  @Override
  public int hashCode() {
    // hash值通過final定義的age計算
    return Objects.hash(age);
  }
}

控制臺輸出:

11

小總結

WeakHashMap 在某些情況下因為 key 是弱引用,所以會導致內存溢出。

ThreadLocal 為什么會內存溢出呢?

就是因為其內部類 Entry 繼承了 WeakReference ,所以一般使用完成之后要及時的 remove HashMap在某些情況下也會內存溢出,所以在自定義類的時候要注意重寫equals和hashcode方法。

到此這篇關于Java中的HashMap內存泄漏問題詳解的文章就介紹到這了,更多相關HashMap內存泄漏內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java使用Random類生成隨機數示例

    Java使用Random類生成隨機數示例

    這篇文章主要介紹了Java使用Random類生成隨機數,結合實例形式分析了java基于Random類生成隨機數與遍歷輸出相關操作技巧,需要的朋友可以參考下
    2019-07-07
  • Java之stream流求字段累計和的3種方法總結

    Java之stream流求字段累計和的3種方法總結

    Java中Stream流用來幫助處理集合,類似于數據庫中的操作,下面這篇文章主要介紹了Java之stream流求字段累計和的3種方法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2025-09-09
  • 關于Java下奇怪的Base64詳解

    關于Java下奇怪的Base64詳解

    這篇文章主要給大家介紹了關于Java下奇怪的Base64的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • Mybatis返回int或者Integer類型報錯的解決辦法

    Mybatis返回int或者Integer類型報錯的解決辦法

    這篇文章主要介紹了Mybatis返回int或者Integer類型報錯的解決辦法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-12-12
  • Java集合排序規(guī)則接口Comparator用法解析

    Java集合排序規(guī)則接口Comparator用法解析

    這篇文章主要介紹了Java集合排序規(guī)則接口Comparator用法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-09-09
  • logback-spring.xml配置解析(最新整理)

    logback-spring.xml配置解析(最新整理)

    logback-spring.xml用于配置Spring?Boot項目日志,定義輸出格式、路徑、級別,支持動態(tài)參數讀?。ㄈ鏢pringProperty),實現日志隔離與滾動策略(按天+大小),并通過logger繼承機制控制日志輸出目的地,對logback-spring.xml配置相關知識感興趣的朋友一起看看吧
    2025-07-07
  • Java發(fā)展史之Java由來

    Java發(fā)展史之Java由來

    本文主要給大家簡單講解了一下java的發(fā)展史,詳細說明了java的由來以及如何一步步發(fā)展起來的,想了解的小伙伴可以來參考下
    2016-10-10
  • Java拆箱與裝箱實例詳解

    Java拆箱與裝箱實例詳解

    這篇文章主要介紹了Java拆箱與裝箱,結合實例形式詳細分析了Java拆箱與裝箱相關的數據類型轉換操作技巧,需要的朋友可以參考下
    2019-11-11
  • SpringBoot整合weixin-java-pay實現微信小程序支付的示例代碼

    SpringBoot整合weixin-java-pay實現微信小程序支付的示例代碼

    微信小程序支付是常見的一種功能,本文主要介紹了SpringBoot整合weixin-java-pay實現微信小程序支付的示例代碼,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧
    2024-05-05
  • java環(huán)境變量如何配置

    java環(huán)境變量如何配置

    這篇文章主要為大家詳細介紹了java環(huán)境變量配置教程,感興趣的小伙伴們可以參考一下
    2016-06-06

最新評論

固原市| 东阿县| 高密市| 化德县| 兴文县| 吴江市| 宝兴县| 临漳县| 巴塘县| 综艺| 长武县| 仁化县| 资兴市| 桂阳县| 邢台县| 定结县| 迁安市| 郑州市| 广丰县| 贵南县| 根河市| 静乐县| 内江市| 沙田区| 镇原县| 晋城| 宜良县| 苗栗县| 冷水江市| 无为县| 平泉县| 华宁县| 松滋市| 常州市| 新巴尔虎右旗| 顺平县| 巴马| 自治县| 横峰县| 修武县| 古蔺县|