java內存泄露排查思路,內存泄露和溢出的區別_Java 中的內存溢出和內存泄露是什么?我給你舉個有味道的例子?...

 2023-10-04 阅读 30 评论 0

摘要:JAVA中的內存溢出和內存泄露分別是什么,有什么聯系和區別,讓我們來看一看。內存泄漏 & 內存溢出1. 內存泄漏(memory leak )java內存泄露排查思路、申請了內存用完了不釋放,比如一共有 1024M 的內存,分配了 521M 的內存一直不回收,那么

JAVA中的內存溢出和內存泄露分別是什么,有什么聯系和區別,讓我們來看一看。

b1112fc569eb5090a9f19db48e01a04b.png

內存泄漏 & 內存溢出

1. 內存泄漏(memory leak )

java內存泄露排查思路、申請了內存用完了不釋放,比如一共有 1024M 的內存,分配了 521M 的內存一直不回收,那么可以用的內存只有 521M 了,仿佛泄露掉了一部分;

通俗一點講的話,內存泄漏就是【占著茅坑不拉shi】。

2. 內存溢出(out of memory)

內存溢出和內存泄漏的區別,申請內存時,沒有足夠的內存可以使用;

通俗一點兒講,一個廁所就三個坑,有兩個站著茅坑不走的(內存泄漏),剩下最后一個坑,廁所表示接待壓力很大,這時候一下子來了兩個人,坑位(內存)就不夠了,內存泄漏變成內存溢出了。

可見,內存泄漏和內存溢出的關系:內存泄露的增多,最終會導致內存溢出。

java內存泄露的最直接表現。這是一個很有味道的例子。

1c945dbebeee4d7018168e6770ea7fcf.png

如上圖:

對象 X 引用對象 Y,X 的生命周期比 Y 的生命周期長;

linux內存溢出排查、那么當Y生命周期結束的時候,X依然引用著Y,這時候,垃圾回收期是不會回收對象Y的;

如果對象X還引用著生命周期比較短的A、B、C,對象A又引用著對象 a、b、c,這樣就可能造成大量無用的對象不能被回收,進而占據了內存資源,造成內存泄漏,直到內存溢出。

泄漏的分類

  • 經常發生:發生內存泄露的代碼會被多次執行,每次執行,泄露一塊內存;
  • 偶然發生:在某些特定情況下才會發生;
  • 一次性:發生內存泄露的方法只會執行一次;
  • 隱式泄露:一直占著內存不釋放,直到執行結束;嚴格的說這個不算內存泄露,因為最終釋放掉了,但是如果執行時間特別長,也可能會導致內存耗盡。

導致內存泄漏的常見原因

1. 循環過多或死循環,產生大量對象;

java內存溢出的幾種原因和解決辦法。2. 靜態集合類引起內存泄漏,因為靜態集合的生命周期和 JVM 一致,所以靜態集合引用的對象不能被釋放;下面這個例子中,list 是靜態的,只要 JVM 不停,那么 obj 也一直不會釋放。

public class OOM {   static List list = new ArrayList();   public void oomTests(){    Object obj = new Object();    list.add(obj);   }}

3. 單例模式,和靜態集合導致內存泄露的原因類似,因為單例的靜態特性,它的生命周期和 JVM 的生命周期一樣長,所以如果單例對象如果持有外部對象的引用,那么這個外部對象也不會被回收,那么就會造成內存泄漏。

4. 數據連接、IO、Socket連接等等,它們必須顯示釋放(用代碼 close 掉),否則不會被 GC 回收。

try {   Connection conn = null;   Class.forName("com.mysql.jdbc.Driver");   conn = DriverManager.getConnection("url","", "");   Statement stmt = conn.createStatement() ;   ResultSet rs = stmt.executeQuery("....") ; } catch (Exception e) { //異常日志} finally {   //1.關閉結果集 Statement   //2.關閉聲明的對象 ResultSet   //3.關閉連接 Connection}

5. 內部類的對象被長期持有,那么內部類對象所屬的外部類對象也不會被回收。

6. Hash 值發生改變,比如下面中的這個類,它的 hashCode 會隨著變量 x 的變化而變化:

public class ChangeHashCode {   private int x ;   @Override   public int hashCode() {      final int prime = 31;      int result = 1;      result = prime * result + x;      return result;   }   @Override   public boolean equals(Object obj) {      if (this == obj)       return true;      if (obj == null)       return false;      if (getClass() != obj.getClass())       return false;      ChangeHashCode other = (ChangeHashCode) obj;      if (x != other.x)       return false;      return true;   } //省略 set 、get 方法}
public class HashSetTests {   public static void main(String[] args){      HashSet hs = new HashSet();      ChangeHashCode cc = new ChangeHashCode();      cc.setX(10);//hashCode = 41      hs.add(cc);      cc.setX(20);//hashCode = 51      System.out.println("hs.remove = " + hs.remove(cc));//false      hs.add(cc);      System.out.println("hs.size = " + hs.size());//size = 2   }}

可以看到,在測試方法中,當元素的 hashCode 發生改變之后,就再也找不到改變之前的那個元素了;

這也是 String 為什么被設置成了不可變類型,我們可以放心地把 String 存入 HashSet,或者把 String 當做 HashMap 的 key 值;

當我們想把自己定義的類保存到散列表的時候,需要保證對象的 hashCode 不可變。

7. 內存中加載數據量過大;之前項目在一次上線的時候,應用啟動奇慢直到夯死,就是因為代碼中會加載一個表中的數據到緩存(內存)中,測試環境只有幾百條數據,但是生產環境有幾百萬的數據。

85a6adbbb6df5e91370cbe4892297793.png

我將持續分享Java開發、架構設計、程序員職業發展等方面的見解,希望能得到你的關注;關注我后,可私信發送數字【1】,獲取學習資料。

c7f45da448433061006df7c0d65235f7.png

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/3/112849.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息