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

Java內存泄漏問題排查與解決

 更新時間:2022年01月26日 15:16:40   作者:文曉武  
大家好,本篇文章主要講的是Java內存泄漏問題排查與解決,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下

前言

Java 最牛逼的一個特性就是垃圾回收機制,不用像 C++ 需要手動管理內存,所以作為 Java 程序員很幸福,只管 New New New 即可,反正 Java 會自動回收過期的對象。。。

那么 Java 都自動管理內存了,那怎么會出現內存泄漏,難道 Jvm 有 bug? 不要急,且聽我慢慢道來。。

1. 怎么判斷可以被回收

先了解一下 Jvm 是怎么判斷一個對象可以被回收。一般有兩種方式,一種是引用計數法,一種是可達性分析。

引用計數法:每個對象有一個引用計數屬性,新增一個引用時計數加1,引用釋放時計數減1,計數為0時可以回收。

這個辦法看起來挺簡單的,但是如果出現 A 引用了 B,B 又引用了 A,這時候就算他們都不再使用了,但因為相互引用 計算器=1 永遠無法被回收。

此方法簡單,無法解決對象相互循環(huán)引用的問題。

可達性分析(Reachability Analysis):從 GC Roots 開始向下搜索,搜索所走過的路徑稱為引用鏈。當一個對象到 GC Roots 沒有任何引用鏈相連時,則證明此對象是不可用的,那么虛擬機就判斷是可回收對象。

可達性分析可以解決循環(huán)引用的問題。

那么 gc roots 對象是哪些呢

虛擬機棧中引用的對象

方法區(qū)中類靜態(tài)屬性引用的對象

方法區(qū)中常量引用的對象

本地方法棧中JNI[即一般說的Native]引用的對象

目前主流的虛擬機中大多使用可達性分析的方式來判定對象是否可被 GC 回收。

2. 什么情況下會出現內存泄漏

既然可達性分析好像已經很牛逼的樣子了,怎么可能還會出現內存泄漏呢,那我們再來看一下內存泄漏的定義。

內存泄露就是指一個不再被程序使用的對象或變量一直被占據在內存中。

有可能此對象已經不使用了,但是還有其它對象保持著此對象的引用,就會導致 GC 不能回收此對象,這種情況下就會出現內存泄漏。

寫一個程序讓出現內存泄漏

①長生命周期的對象持有短生命周期對象的引用就很可能發(fā)生內存泄露,盡管短生命周期對象已經不再需要,但是因為長生命周期對象持有它的引用而導致不能被回收。

public class Simple {
    Object object;
    public void method1(){
        object = new Object();
        //...其他代碼
    }
}

這里的 object 實例,其實我們期望它只作用于 method1() 方法中,且其他地方不會再用到它,但是,當method1()方法執(zhí)行完成后,object 對象所分配的內存不會馬上被認為是可以被釋放的對象,只有在 Simple 類創(chuàng)建的對象被釋放后才會被釋放,嚴格的說,這就是一種內存泄露。

解決方法就是將 object 作為 method1() 方法中的局部變量。

public class Simple {
    Object object;
    public void method1(){
        object = new Object();
        //...其他代碼
        object = null;
    }
}

當然大家有可能會想就這一個方法也不會有多大影響,但如果在某些項目中,一個方法在一分鐘之內調用上萬次的時候,就會出現很明顯的內存泄漏現象。

②集合中的內存泄漏,比如 HashMap、ArrayList 等,這些對象經常會發(fā)生內存泄露。比如當它們被聲明為靜態(tài)對象時,它們的生命周期會跟應用程序的生命周期一樣長,很容易造成內存不足。

下面給出了一個關于集合內存泄露的例子。

Vector v=new Vector(10);
for (int i=1;i<100; i++)
{
    Object o=new Object();
    v.add(o);
    o=null;
}
//此時,所有的Object對象都沒有被釋放,因為變量v引用這些對象。

在這個例子中,我們循環(huán)申請 Object 對象,并將所申請的對象放入一個 Vector 中,如果我們僅僅釋放引用本身,那么 Vector 仍然引用該對象,所以這個對象對 GC 來說是不可回收的。

因此,如果對象加入到 Vector 后,還必須從 Vector 中刪除,最簡單的方法就是將 Vector 對象設置為 null。

以上兩種是最常見的內存泄漏案例。當然還有一些內存泄漏的例子,這里就不再一一例舉了,感興趣的同學可以在網上找找資料。

3. 如何檢測內存泄漏

3.1 模擬內存泄漏代碼

package com.wenxiaowu.solution;
 
import java.util.ArrayList;
import java.util.List;
 
/**
 * Java 內存泄露模擬
 */
public class TestMemoryLeak {
    public static void main(String[] args) throws InterruptedException {
        List<SimpleObject> list = new ArrayList<>();
        Runtime run = Runtime.getRuntime();
        int i = 1;
 
        while (true) {
            SimpleObject simpleObject = new SimpleObject();
            list.add(simpleObject);
            simpleObject = null;
 
            if (i++ % 1000 == 0) {
                System.out.print(i + ": 最大內存=" + run.maxMemory() / 1024 / 1024 + "M,");
                System.out.print("已分配內存=" + run.totalMemory() / 1024 / 1024 + "M,");
                System.out.print("剩余空間內存=" + run.freeMemory() / 1024 / 1024 + "M");
                System.out.println("最大可用內存=" + (run.maxMemory() - run.totalMemory() + run.freeMemory()) / 1024 / 1024 + "M");
            }
            Thread.sleep(1);
        }
    }
}
 
class SimpleObject {
    // 初始化占用1M內存的數組
    private int[] arr = new int[1024 * 8];
    public int[] getArr() {
        return arr;
    }
}

3.2 生成dump文件

java -jar -Xmx1G -Xms1G -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp wenxiaowu-java.jar

3.3 用JProfile加載dump文件

可以看到,紅框處的int數組占用空間最大

3.4 定位最大占用內存的原始位置

最終找到這個對象是在main方法中創(chuàng)建的。

解決辦法 

使用完之后,先刪除對應的引用,再將對象置為null,即可正常進行內存回收。

總結

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

相關文章

  • Java RabbitMQ的TTL和DLX全面精解

    Java RabbitMQ的TTL和DLX全面精解

    過期時間TTL表示可以對消息設置預期的時間,在這個時間內都可以被消費者接收獲??;過了之后消息將自動被刪除。DLX, 可以稱之為死信交換機,當消息在一個隊列中變成死信之后,它能被重新發(fā)送到另一個交換機中,這個交換機就是DLX ,綁定DLX的隊列就稱之為死信隊列
    2021-09-09
  • Java的WeakHashMap源碼解析及使用場景詳解

    Java的WeakHashMap源碼解析及使用場景詳解

    這篇文章主要介紹了Java的WeakHashMap源碼解析及使用場景詳解,Map本身生命周期很長,需要長期貯留內存中,但Map中的Entry可以刪除,使用時可以從其它地方再次取得,需要的朋友可以參考下
    2023-09-09
  • SpringBoot實現PDF添加水印的三種方法

    SpringBoot實現PDF添加水印的三種方法

    本文主要介紹了SpringBoot實現PDF添加水印的三種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-07-07
  • 兩個jar包下相同包名類名引入沖突的解決方法

    兩個jar包下相同包名類名引入沖突的解決方法

    本文主要介紹了兩個jar包下相同包名類名引入沖突的解決方法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • SpringMVC前后端參數映射

    SpringMVC前后端參數映射

    在web開發(fā)中我們都要進行前端傳參后端取參的過程,本文主要介紹了SpringMVC前后端參數映射,針對GET,?POST,?PUT,?DELETE?請求的參數該如何映射,感興趣的可以了解一下
    2023-08-08
  • 圖書管理系統(tǒng)java版

    圖書管理系統(tǒng)java版

    這篇文章主要為大家詳細介紹了java版的圖書管理系統(tǒng),通過實例為大家快速掌握數據庫編程技術,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Java 匿名對象與匿名內部類的使用

    Java 匿名對象與匿名內部類的使用

    很多小伙伴對匿名對象和匿名內部類的寫法有點陌生,本文主要介紹了Java 匿名對象與匿名內部類的使用,具有一定的參考價值,感興趣的可以了解一下
    2024-01-01
  • @insert mybatis踩坑記錄,實體接收前端傳遞的參數

    @insert mybatis踩坑記錄,實體接收前端傳遞的參數

    這篇文章主要介紹了@insert mybatis踩坑記錄,實體接收前端傳遞的參數問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • java開發(fā)之Jdbc分頁源碼詳解

    java開發(fā)之Jdbc分頁源碼詳解

    這篇文章主要介紹了java開發(fā)之Jdb分頁源碼詳解,需要的朋友可以參考下
    2020-02-02
  • 解決SpringMVC 返回Java8 時間JSON數據的格式化問題處理

    解決SpringMVC 返回Java8 時間JSON數據的格式化問題處理

    本篇文章主要介紹了解決SpringMVC 返回Java8 時間JSON數據的格式化問題處理,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02

最新評論