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

深入聊聊Java內(nèi)存泄露問題

 更新時間:2022年04月02日 15:08:41   作者:llsydn  
所謂內(nèi)存泄露就是指一個不再被程序使用的對象或變量一直被占據(jù)在內(nèi)存中,下面這篇文章主要給大家介紹了關(guān)于Java內(nèi)存泄露問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下

Java內(nèi)存泄露問題

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

Java 中有垃圾回收機制,它可以保證一對象不再被引用的時候,即對象變成了孤兒的時候,對象將自動被垃圾回收器從內(nèi)存中清除掉。

既然java有垃圾回收機制,為什么還會存在內(nèi)存泄漏的問題呢?

無非,就是有些對象,無法被垃圾回收器處理,導(dǎo)致這些對象一直占用JVM內(nèi)存,那不就導(dǎo)致內(nèi)存泄漏了嘛。

由于 Java 使用有向圖的方式進行垃圾回收管理,可以消除引用循環(huán)的問題 ,例如有兩個對象 ,相互引用, 只要它們和根進程不可達的,那么GC也是可以回收它們的,例如下面的代碼可以看到這種情況的內(nèi)存回收。

import java. io.IOException;
public class GarbageTest {

    public static void main(String[] args) throws IOException {
        try {
            // TODO Auto-generated method stub
            gcTest();
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("has exited gcTest!");
        System.in.read();
        System.in.read();
        System.out.println("out begin gc!");
        for (int i = 0; i < 100; i++) {
            System.gc();
            System.in.read();
            System.in.read();
        }
    }

    private static void gcTest() throws IOException {
        System.in.read();
        System.in.read();
        Person p1 = new Person();
        System.in.read();
        System.in.read();
        Person p2 = new Person();
        p1.setMate(p2);
        p2.setMate(p1);
        System.out.println("before exit gctest!");
        System.in.read();
        System.in.read();
        System.gc();
        System.out.println("exit gctest!");
    }

    private static class Person {
        byte[] data = new byte[20000000];
        Person mate = null;

        public void setMate(Person other) {
            mate = other;
        }
    }

}

Java 中的內(nèi)存泄露的情況: 長生命周期的對象持有短生命周期對象的引用就很可能發(fā)生內(nèi)存泄露,盡管短室命周期對象已經(jīng)不再需要,但是因為長生命周期對象持有它的引用而導(dǎo)致不能被回收,這就是 Java 中內(nèi)存泄露的發(fā)室場景 ,通俗地說,就是程序員可能創(chuàng)建了一個對象,以后一直不再使用這個對象,這個對象卻一直被引用,即這個對象無用但是卻無法被垃圾回收器回收的,這就是 java 中可能出現(xiàn)內(nèi)存泄露的情況。

例如,緩存系統(tǒng),我們加載了一個對象放在緩存中 (例如放在一個全局map對象中),然后一直不再使用它,這個對象一值被緩存引用, 但卻不再被便用。

檢查 Java 中的內(nèi)存泄露,一定要讓程序?qū)⒏鞣N分支情況都完整執(zhí)行到程序結(jié)束,然后看某個對象是否被使用過,如果沒有,則才能判定這個對象屬于內(nèi)存泄露。

如果一個外部類的實例對象的方法返回了一個內(nèi)部類的實例對象,這個內(nèi)部類對象被長期引用了,即使那個外部類實例對象不再被使用,但由于內(nèi)部類持久外部類的實例對象,這個外部類對象將不會被垃圾回收,這也會造成內(nèi)存泄露.

下面內(nèi)容來自于網(wǎng)上 (主要特點就是清空堆棧中的某個元素,并不是徹底把它從數(shù)組中拿掉,而是把存儲的總數(shù)減少,本人寫得可以比這個好,在拿掉某個元素時,順便也讓它從數(shù)組中消失,將那個元素所在的位置的值設(shè)置為 null 即可)

我實在想不到比那個堆棧更經(jīng)典的例子了,以致于我還要引用別人的例子,下面的例子不是我想到的,是書上看到的 ,當然如果沒有在書上看到,可能過一段時間我自己也想的到,可是那時我說是我自己想到的也沒有人相信的。

public class Stack {
    private Object[] elements = new Object[10];
    private int size = 0;

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop() {
        if (size == 0) throw new EmptyStackException();
        return elements[--size];
    }

    private void ensureCapacity() {
        if (elements.length == size) {
            Object[] oldElements = elements;
            elements = new Object[2 * elements.length + 1];
            System.arraycopy(oldElements, 0, elements, 0, size);
        }
    }
}

上面的原理應(yīng)該很簡單,假如堆錢加了10 個元素 ,然后全部彈出來 ,雖然堆錢是空的,沒有我們要的東西,但是這是個對象是無法回收的,這個才符合了內(nèi)存泄露的兩個條件 無用,無法回收。 但是就是存在這樣的東西也不一定會導(dǎo)致什么樣的后果 ,如果這個堆錢用的比較少,也就浪費了幾個 K 內(nèi)存而己,反正我們 的內(nèi)存都上 G 了,哪里會有什么影響,再說這個東西很快就會被回收的,有什么關(guān)系。 下面看兩個例子。

class Bad {
    public static Stack s = new Stack();
    static {
        s.push(new Object());

        s.pop(); //這里有一個對象發(fā)生內(nèi)存泄露

        s.push(new Object());//上面的對象可以被回收了,等于是自愈了
    }
}

因為是 static ,就一直存在 到程序退出,但是我們也可以看到它有自愈功能,就是說如果你的 Stack 最多有 100 個對象,那么最多也就只有 100 個對象無法 被回收, 其實這個應(yīng)該很容易理解,Stack 內(nèi)部持有 100 個引用,最壞的情況就是 他們都是無用的,因為我們一旦放新的進取,以前的引用自然消失!

內(nèi)存泄露的另外一種情況: 當一個對象被存儲進 HashSet 集合中以后,就不能修改這個對象中的那些參與計算哈希值的字段了,否則,對象修改后的晗希值與 最初存儲進 HashSet 集合中時的哈希值就不同了,在這種情況下,即使在 contains 方法使用該對象的當前引用作為的參數(shù)去 HashSet 集合中檢索對象, 也將返回找不到對象的結(jié)果,這也會導(dǎo)致無法從 HashSet 集合中單獨刪除當前對象,造成內(nèi)存泄露。

附:內(nèi)存泄露的典型情況

(1) 數(shù)據(jù)結(jié)構(gòu)造成的短暫內(nèi)存泄露問題,看下面的代碼

public class Stack{  
      private Object[] element=new Object[10];  
      private int size=0;  
        
      public void push(Object ele){  
             ensureCapacity();  
             element[size++]=ele;  
      }  
  
      public Object pop(){  
             if(size==0) throw new EmptyStackException();  
             return element[--size]; //短暫造成內(nèi)存泄露  
      }  
  
      private void ensureCapacity(){  
             if(element.length==size){  
                     Object[] oldElement=element;  
                     element=new Object[size*2+1];  
                     System.arraycopy(oldElement,0,element,0,size);  
             }  
      }  
}  

上面的代碼每一次pop()的時候,Stack都會彈出一個元素,在沒有加入新元素之前,實際上仍然有一個引用element[x]指向了這個已經(jīng)彈出的對象,因此GC是不會對其進行垃圾回收的。只有push()新元素的時候使得element[x]=newObject,才會使得以前創(chuàng)建的對象有可能被回收。應(yīng)該把上面的pop()方法改成下面的代碼就安全多了:

public Object pop(){  
       if(element.length==size) throws EmptyStackException();  
       Object o=element[--size];  
       elements[size]=null;  //使得GC有機會回收這個對象  
       return o;  
}  

總結(jié)

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

相關(guān)文章

  • SpringBoot下的值注入(推薦)

    SpringBoot下的值注入(推薦)

    這篇文章主要介紹了SpringBoot下的值注入(推薦)的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • MyBatis_Generator插件的安裝以及簡單使用方法(圖解)

    MyBatis_Generator插件的安裝以及簡單使用方法(圖解)

    下面小編就為大家?guī)硪黄狹yBatis_Generator插件的安裝以及簡單使用方法(圖解)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • swagger如何返回map字段注釋

    swagger如何返回map字段注釋

    這篇文章主要介紹了swagger如何返回map字段注釋的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • servlet的url-pattern匹配規(guī)則詳細描述(小結(jié))

    servlet的url-pattern匹配規(guī)則詳細描述(小結(jié))

    在利用servlet或Filter進行url請求的匹配時,很關(guān)鍵的一點就是匹配規(guī)則。這篇文章主要介紹了servlet的url-pattern匹配規(guī)則詳細描述(小結(jié)),非常具有實用價值,需要的朋友可以參考下
    2018-07-07
  • Java之遍歷枚舉值問題

    Java之遍歷枚舉值問題

    這篇文章主要介紹了Java之遍歷枚舉值問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 本地編譯打包項目部署到服務(wù)器并且啟動方式

    本地編譯打包項目部署到服務(wù)器并且啟動方式

    這篇文章主要介紹了本地編譯打包項目部署到服務(wù)器并且啟動方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Java Spring 控制反轉(zhuǎn)(IOC)容器詳解

    Java Spring 控制反轉(zhuǎn)(IOC)容器詳解

    這篇文章主要為大家詳細介紹了Spring控制反轉(zhuǎn)IoC入門使用的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Mybatis全局配置及映射關(guān)系的實現(xiàn)

    Mybatis全局配置及映射關(guān)系的實現(xiàn)

    本文主要介紹了Mybatis全局配置及映射關(guān)系的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • java 中http請求為了防止亂碼解決方案

    java 中http請求為了防止亂碼解決方案

    這篇文章主要介紹了java 中http請求為了防止亂碼解決方案的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • 優(yōu)雅地在Java 8中處理異常的方法詳解

    優(yōu)雅地在Java 8中處理異常的方法詳解

    異常處理是我們在日常開發(fā)中經(jīng)常會遇到的一種需求,下面這篇文章主要給大家介紹了關(guān)于如何優(yōu)雅地在Java 8中處理異常的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們來一起看看吧
    2019-01-01

最新評論