java代碼優(yōu)化——消除過期的對象引用

很多人可能在想這么一個(gè)問題:Java有垃圾回收機(jī)制,那么還存在內(nèi)存泄露嗎?答案是肯定的,所謂的垃圾回收GC會(huì)自動(dòng)管理內(nèi)存的回收,而不需要程序員每次都手動(dòng)釋放內(nèi)存,但是如果存在大量的臨時(shí)對象在不需要使用時(shí)并沒有取消對它們的引用,就會(huì)吞噬掉大量的內(nèi)存,很快就會(huì)造成內(nèi)存溢出。

一、Java的垃圾回收機(jī)制

Java中的對象是在堆中分配,對象的創(chuàng)建有2中方式:new或者反射。對象的回收是通過垃圾收集器,JVM的垃圾收集器簡化了程序員的工作,但是卻加重了JVM的工作,這是Java程序運(yùn)行稍慢的原因之一,因?yàn)镚C為了能正確釋放對象,必須監(jiān)控每一個(gè)對象的運(yùn)行狀態(tài),包括對象的申請、引用、被引用、賦值等,GC都要進(jìn)行監(jiān)控,監(jiān)控對象的狀態(tài)是為了更加準(zhǔn)確、及時(shí)地釋放對象,而釋放對象的根本原則就是該對象不再被引用。

三、Java中的內(nèi)存泄露

內(nèi)存泄露的對象有以下兩個(gè)特點(diǎn):

① 這些對象是可達(dá)的,即在有向圖中存在通路可以與其相連。
② 這些對象是無用的,即程序以后都不會(huì)再使用這些對象。

public class Stack {  
    private final static int MAX_ATTRIBUTE = 10;  
    private Object[] arr;  
    private int index = 0; 
    public void push(Object obj) {  
        if (index > 9)  
            throw new IllegalArgumentException();  
        arr[index] = obj;  
        index++;  
    }  
    public Stack() {  
        arr = new Object[MAX_ATTRIBUTE];  
    }  
    public Object pop() {  
        if (index < 0)  
            throw new IllegalArgumentException();  
        return arr[--index];  
    }  
}  

這個(gè)程序那里發(fā)生了內(nèi)存泄露呢?如果一個(gè)棧先增長然后收縮,那么從棧中彈出來的對象將不會(huì)被當(dāng)做垃圾回收,即使使用棧的程序不再引用這些對象,它們也不會(huì)被回收,因?yàn)闂?nèi)部維護(hù)這對這些對象的過期引用。

public Object pop() {    
    if (size == 0)    
        throw new EmptyStackException();    
    Object result = elements[--size];    
    elements[size] = null; //Eliminate obsolete reference       
    return result;    
}    

解決辦法:只要一個(gè)元素被彈出棧,那么就將它的引用置為空,GC就會(huì)回收。即一旦數(shù)組元素變成了非活動(dòng)部分的一部分,就手工清空這些數(shù)組元素。

不要被類似的問題困擾

當(dāng)程序員第一次被類似這樣的問題困擾的時(shí)候,他們往往會(huì)過分小心;對于每一個(gè)對象引用,一旦不再使用它,就把它清空,這是沒有必要的,這樣反而會(huì)把代碼弄的混亂。清空對象的引用應(yīng)該是一種例外(因?yàn)樗鼉H在一些特殊的情況下才需要進(jìn)行),而不是一種規(guī)范行為。消除過期引用最好的辦法是讓包含該引用的變量結(jié)束其生命周期。如果是在最緊湊的作用域范圍內(nèi)定義每一個(gè)變量,這種情況就會(huì)自然而然地發(fā)生。
一般而言,只要類是自己管理內(nèi)存,就應(yīng)該警惕內(nèi)存泄漏問題。一旦元素被釋放掉,則該元素中包含的任何對象引用都應(yīng)該被清空。

四、常見的內(nèi)存泄露

① 緩存。一旦你把對象引用放到緩存中,它就很容易被遺忘掉,從而使得它不再有用之后很長一段時(shí)間內(nèi)仍然留在緩存中。
② 在Java程序中,我們經(jīng)常要和監(jiān)聽器打交道,通常調(diào)用諸如addXXXListener()等方法來增加監(jiān)聽器,但往往忘記刪除這些監(jiān)聽器,從而增加了內(nèi)存泄漏的機(jī)會(huì)。
③ 使用連接池時(shí),除了要顯式地關(guān)閉連接,還必須顯式地關(guān)閉Resultset和Statement對象。否則會(huì)造成大量的這些對象無法釋放,從而引起內(nèi)存泄露。
④ 盡量少用靜態(tài)變量,因?yàn)殪o態(tài)變量存放在永久代,永久代基本不參與垃圾回收

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容