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

Java內(nèi)存泄漏問(wèn)題排查與解決

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

前言

Java 最牛逼的一個(gè)特性就是垃圾回收機(jī)制,不用像 C++ 需要手動(dòng)管理內(nèi)存,所以作為 Java 程序員很幸福,只管 New New New 即可,反正 Java 會(huì)自動(dòng)回收過(guò)期的對(duì)象。。。

那么 Java 都自動(dòng)管理內(nèi)存了,那怎么會(huì)出現(xiàn)內(nèi)存泄漏,難道 Jvm 有 bug? 不要急,且聽我慢慢道來(lái)。。

1. 怎么判斷可以被回收

先了解一下 Jvm 是怎么判斷一個(gè)對(duì)象可以被回收。一般有兩種方式,一種是引用計(jì)數(shù)法,一種是可達(dá)性分析。

引用計(jì)數(shù)法:每個(gè)對(duì)象有一個(gè)引用計(jì)數(shù)屬性,新增一個(gè)引用時(shí)計(jì)數(shù)加1,引用釋放時(shí)計(jì)數(shù)減1,計(jì)數(shù)為0時(shí)可以回收。

這個(gè)辦法看起來(lái)挺簡(jiǎn)單的,但是如果出現(xiàn) A 引用了 B,B 又引用了 A,這時(shí)候就算他們都不再使用了,但因?yàn)橄嗷ヒ?計(jì)算器=1 永遠(yuǎn)無(wú)法被回收。

此方法簡(jiǎn)單,無(wú)法解決對(duì)象相互循環(huán)引用的問(wèn)題。

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

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

那么 gc roots 對(duì)象是哪些呢

虛擬機(jī)棧中引用的對(duì)象

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

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

本地方法棧中JNI[即一般說(shuō)的Native]引用的對(duì)象

目前主流的虛擬機(jī)中大多使用可達(dá)性分析的方式來(lái)判定對(duì)象是否可被 GC 回收。

2. 什么情況下會(huì)出現(xiàn)內(nèi)存泄漏

既然可達(dá)性分析好像已經(jīng)很牛逼的樣子了,怎么可能還會(huì)出現(xiàn)內(nèi)存泄漏呢,那我們?cè)賮?lái)看一下內(nèi)存泄漏的定義。

內(nèi)存泄露就是指一個(gè)不再被程序使用的對(duì)象或變量一直被占據(jù)在內(nèi)存中。

有可能此對(duì)象已經(jīng)不使用了,但是還有其它對(duì)象保持著此對(duì)象的引用,就會(huì)導(dǎo)致 GC 不能回收此對(duì)象,這種情況下就會(huì)出現(xiàn)內(nèi)存泄漏。

寫一個(gè)程序讓出現(xiàn)內(nèi)存泄漏

①長(zhǎng)生命周期的對(duì)象持有短生命周期對(duì)象的引用就很可能發(fā)生內(nèi)存泄露,盡管短生命周期對(duì)象已經(jīng)不再需要,但是因?yàn)殚L(zhǎng)生命周期對(duì)象持有它的引用而導(dǎo)致不能被回收。

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

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

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

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

當(dāng)然大家有可能會(huì)想就這一個(gè)方法也不會(huì)有多大影響,但如果在某些項(xiàng)目中,一個(gè)方法在一分鐘之內(nèi)調(diào)用上萬(wàn)次的時(shí)候,就會(huì)出現(xiàn)很明顯的內(nèi)存泄漏現(xiàn)象。

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

下面給出了一個(gè)關(guān)于集合內(nèi)存泄露的例子。

Vector v=new Vector(10);
for (int i=1;i<100; i++)
{
    Object o=new Object();
    v.add(o);
    o=null;
}
//此時(shí),所有的Object對(duì)象都沒有被釋放,因?yàn)樽兞縱引用這些對(duì)象。

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

因此,如果對(duì)象加入到 Vector 后,還必須從 Vector 中刪除,最簡(jiǎn)單的方法就是將 Vector 對(duì)象設(shè)置為 null。

以上兩種是最常見的內(nèi)存泄漏案例。當(dāng)然還有一些內(nèi)存泄漏的例子,這里就不再一一例舉了,感興趣的同學(xué)可以在網(wǎng)上找找資料。

3. 如何檢測(cè)內(nèi)存泄漏

3.1 模擬內(nèi)存泄漏代碼

package com.wenxiaowu.solution;
 
import java.util.ArrayList;
import java.util.List;
 
/**
 * Java 內(nèi)存泄露模擬
 */
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 + ": 最大內(nèi)存=" + run.maxMemory() / 1024 / 1024 + "M,");
                System.out.print("已分配內(nèi)存=" + run.totalMemory() / 1024 / 1024 + "M,");
                System.out.print("剩余空間內(nèi)存=" + run.freeMemory() / 1024 / 1024 + "M");
                System.out.println("最大可用內(nèi)存=" + (run.maxMemory() - run.totalMemory() + run.freeMemory()) / 1024 / 1024 + "M");
            }
            Thread.sleep(1);
        }
    }
}
 
class SimpleObject {
    // 初始化占用1M內(nèi)存的數(shù)組
    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數(shù)組占用空間最大

3.4 定位最大占用內(nèi)存的原始位置

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

解決辦法 

使用完之后,先刪除對(duì)應(yīng)的引用,再將對(duì)象置為null,即可正常進(jìn)行內(nèi)存回收。

總結(jié)

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

相關(guān)文章

  • 關(guān)于Java集合框架Collection接口詳解

    關(guān)于Java集合框架Collection接口詳解

    這篇文章主要介紹了關(guān)于Java集合框架Collection接口詳解,Collection接口是Java集合框架中的基礎(chǔ)接口,定義了一些基本的集合操作,包括添加元素、刪除元素、遍歷集合等,需要的朋友可以參考下
    2023-05-05
  • java使用zookeeper實(shí)現(xiàn)的分布式鎖示例

    java使用zookeeper實(shí)現(xiàn)的分布式鎖示例

    這篇文章主要介紹了java使用zookeeper實(shí)現(xiàn)的分布式鎖示例,需要的朋友可以參考下
    2014-05-05
  • 最新評(píng)論

    平邑县| 上高县| 长寿区| 盐亭县| 宣城市| 太白县| 临邑县| 敦化市| 陇西县| 六枝特区| 垣曲县| 荣昌县| 土默特左旗| 定陶县| 霍林郭勒市| 渝北区| 武义县| 茂名市| 兴城市| 郴州市| 遂昌县| 即墨市| 彰化县| 麻城市| 五峰| 固始县| 肃北| 石台县| 永定县| 平邑县| 县级市| 海淀区| 温州市| 青田县| 葫芦岛市| 抚松县| 新余市| 湖州市| 福安市| 乌海市| 五峰|