<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 495,comments - 227,trackbacks - 0

    歐陽辰 (yeekee@sina.com)
    周欣 (zhouxin@sei.pku.edu.cn)

    垃圾收集器(Garbage Collector,GC)對Java程序員來說,基本 上是透明的,但是一個優秀的Java程序員必須了解GC的工作原理、如何優化GC的性能、如何與GC進行有限的交互,因為有一些應用程序對性能要求較高,例如嵌入式系統、實時系統等,只有全面提升內存的管理效率 ,才能提高整個應用程序的性能。本篇文章首先簡單介紹GC的工作原理之后,然后再對GC的幾個關鍵問題進行深入探討,最后提出一些Java程序設計建議,從GC角度提高Java程序的性能。

    一GC的基本原理

    Java的內存管理實際上就是對象的管理,其中包括對象的分配和釋放。

    對于程序員來說,分配對象使用new關鍵字;釋放對象時,只要將對象所有引用賦值為null,讓程序不能夠再訪問到這個對象,我們稱該對象為"不可達的"。GC將負責回收所有"不可達"對象的內存空間。

    對于GC來說,當程序員創建對象時,GC就開始監控這個對象的地址、大小以及使用情況。通常,GC采用有向圖的方式記錄和管理堆(heap)中的所有對象(詳見參考資料1 )。通過這種方式確定哪些對象是"可達的",哪些對象是"不可達的"。當GC確定一些對象為"不可達"時,GC就有責任回收這些內存空間。但是,為了保證GC能夠在不同平臺實現的問題,Java規范對GC的很多行為都沒有進行嚴格的規定。例如,對于采用什么類型的回收算法、什么時候進行回收等重要問題都沒有明確的規定。因此,不同的JVM的實現者往往有不同的實現算法。這也給Java程序員的開發帶來行多不確定性。本文研究了幾個與GC工作相關的問題,努力減少這種不確定性給Java程序帶來的負面影響。

    二 增量式GC( Incremental GC )

    GC在JVM中通常是由一個或一組進程來實現的,它本身也和用戶程序一樣占用heap空間,運行時也占用CPU。當GC進程運行時,應用程序停止運行。因此,當GC運行時間較長時,用戶能夠感到Java程序的停頓,另外一方面,如果GC運行時間太短,則可能對象回收率太低,這意味著還有很多應該回收的對象沒有被回收,仍然占用大量內存。因此,在設計GC的時候,就必須在停頓時間和回收率之間進行權衡。一個好的GC實現允許用戶定義自己所需要的設置,例如有些內存有限有設備,對內存的使用量非常敏感,希望GC能夠準確的回收內存,它并不在意程序速度的放慢。另外一些實時網絡游戲,就不能夠允許程序有長時間的中斷。增量式GC就是通過一定的回收算法,把一個長時間的中斷,劃分為很多個小的中斷,通過這種方式減少GC對用戶程序的影響。雖然,增量式GC在整體性能上可能不如普通GC的效率高,但是它能夠減少程序的最長停頓時間。

    下圖就表示了,增量式GC和普通GC的比較。其中灰色部分表示線程占用CPU的時間。

     

     

    Sun JDK提供的HotSpot JVM就能支持增量式GC。HotSpot JVM缺省GC方式為不使用增量GC,為了啟動增量GC,我們必須在運行Java程序時增加-Xincgc的參數。HotSpot JVM增量式GC的實現是采用Train GC算法。它的基本想法就是,將堆中的所有對象按照創建和使用情況進行分組(分層),將使用頻繁高和具有相關性的對象放在一隊中,隨著程序的運行,不斷對組進行調整。當GC運行時,它總是先回收最老的(最近很少訪問的)的對象,如果整組都為可回收對象,GC將整組回收。這樣,每次GC運行只回收一定比例的不可達對象,保證程序的順暢運行。Train GC算法是一個非常好的算法,具體算法見參考資料4

    三 詳解finalize函數

    finalize是位于Object類的一個方法,該方法的訪問修飾符為protected,由于所有類為Object的子類,因此用戶類很容易訪問到這個方法。由于,finalize函數沒有自動實現鏈式調用,我們必須手動的實現,因此finalize函數的最后一個語句通常是super.finalize()。通過這種方式,我們可以實現從下到上實現finalize的調用,即先釋放自己的資源,然后再釋放父類的資源。

    根據Java語言規范,JVM保證調用finalize函數之前,這個對象是不可達的,但是JVM不保證這個函數一定會被調用。另外,規范還保證finalize函數最多運行一次。

    很多Java初學者會認為這個方法類似與C++中的析構函數,將很多對象、資源的釋放都放在這一函數里面。其實,這不是一種很好的方式。原因有三,其一,GC為了能夠支持finalize函數,要對覆蓋這個函數的對象作很多附加的工作。其二,在finalize運行完成之后,該對象可能變成可達的,GC還要再檢查一次該對象是否是可達的。因此,使用finalize會降低GC的運行性能。其三,由于GC調用finalize的時間是不確定的,因此通過這種方式釋放資源也是不確定的。

    通常,finalize用于一些不容易控制、并且非常重要資源的釋放,例如一些I/O的操作,數據的連接。這些資源的釋放對整個應用程序是非常關鍵的。在這種情況下,程序員應該以通過程序本身管理(包括釋放)這些資源為主,以finalize函數釋放資源方式為輔,形成一種雙保險的管理機制,而不應該僅僅依靠finalize來釋放資源。

    下面給出一個例子說明,finalize函數被調用以后,仍然可能是可達的,同時也可說明一個對象的finalize只可能運行一次。

     


    class MyObject{
    Test main; //記錄Test對象,在finalize中時用于恢復可達性
    public MyObject(Test t)
    {
    main=t; //保存Test 對象
    }
    protected void finalize()
    {
    main.ref=this;// 恢復本對象,讓本對象可達
    System.out.println("This is finalize");//用于測試finalize只運行一次
    }
    }

    class Test {
    MyObject ref;
    public static void main(String[] args) {
    Test test=new Test();
    test.ref=new MyObject(test);
    test.ref=null; //MyObject對象為不可達對象,finalize將被調用
    System.gc();
    if (test.ref!=null) System.out.println("My Object還活著");
    }
    }

    運行結果:
    This is finalize
    MyObject還活著

    此例子中,需要注意的是雖然MyObject對象在finalize中變成可達對象,但是下次回收時候,finalize卻不再被調用,因為finalize函數最多只調用一次。

    四 程序如何與GC進行交互

    Java2增強了內存管理功能, 增加了一個java.lang.ref包,其中定義了三種引用類。這三種引用類分別為SoftReference、WeakReference和PhantomReference。通過使用這些引用類,程序員可以在一定程度與GC進行交互,以便改善GC的工作效率。這些引用類的引用強度介于可達對象和不可達對象之間。它們的引用強度如下圖所示:

     

     

    創建一個引用對象也非常容易,例如如果你需要創建一個Soft Reference對象,那么首先創建一個對象,并采用普通引用方式(可達對象);然后再創建一個SoftReference引用該對象;最后將普通引用設置為null。通過這種方式,這個對象就只有一個Soft Reference引用。同時,我們稱這個對象為Soft Reference 對象。

    Soft Reference的主要特點是據有較強的引用功能。只有當內存不夠的時候,才進行回收這類內存,因此在內存足夠的時候,它們通常不被回收。另外,這些引用對象還能保證在Java拋出OutOfMemory 異常之前,被設置為null。它可以用于實現一些常用圖片的緩存,實現Cache的功能,保證最大限度的使用內存而不引起OutOfMemory。以下給出這種引用類型的使用偽代碼;

     


    //申請一個圖像對象
    Image image=new Image();//創建Image對象

    //使用 image

    //使用完了image,將它設置為soft 引用類型,并且釋放強引用;
    SoftReference sr=new SoftReference(image);
    image=null;

    //下次使用時
    if (sr!=null) image=sr.get();
    else{
    //由于GC由于低內存,已釋放image,因此需要重新裝載;
    image=new Image();
    sr=new SoftReference(image);
    }

    Weak引用對象與Soft引用對象的最大不同就在于:GC在進行回收時,需要通過算法檢查是否回收Soft引用對象,而對于Weak引用對象,GC總是進行回收。Weak引用對象更容易、更快被GC回收。雖然,GC在運行時一定回收Weak對象,但是復雜關系的Weak對象群常常需要好幾次GC的運行才能完成。Weak引用對象常常用于Map結構中,引用數據量較大的對象,一旦該對象的強引用為null時,GC能夠快速地回收該對象空間。該例子見參考資料4;

    Phantom引用的用途較少,主要用于輔助finalize函數的使用。Phantom對象指一些對象,它們執行完了finalize函數,并為不可達對象,但是它們還沒有被GC回收。這種對象可以輔助finalize進行一些后期的回收工作,我們通過覆蓋Reference的clear()方法,增強資源回收機制的靈活性。

    五一些Java編碼的建議

    根據GC的工作原理,我們可以通過一些技巧和方式,讓GC運行更加有效率,更加符合應用程序的要求。以下就是一些程序設計的幾點建議。

    1. 最基本的建議就是盡早釋放無用對象的引用。大多數程序員在使用臨時變量的時候,都是讓引用變量在退出活動域(scope)后,自動設置為null。我們在使用這種方式時候,必須特別注意一些復雜的對象圖,例如數組,隊列,樹,圖等,這些對象之間有相互引用關系較為復雜。對于這類對象,GC回收它們一般效率較低。如果程序允許,盡早將不用的引用對象賦為null。這樣可以加速GC的工作。
    2. 盡量少用finalize函數。finalize函數是Java提供給程序員一個釋放對象或資源的機會。但是,它會加大GC的工作量,因此盡量少采用finalize方式回收資源。
    3. 如果需要使用經常使用的圖片,可以使用soft應用類型。它可以盡可能將圖片保存在內存中,供程序調用,而不引起OutOfMemory。
    4. 注意集合數據類型,包括數組,樹,圖,鏈表等數據結構,這些數據結構對GC來說,回收更為復雜。另外,注意一些全局的變量,以及一些靜態變量。這些變量往往容易引起懸掛對象(dangling reference),造成內存浪費。
    5. 當程序有一定的等待時間,程序員可以手動執行System.gc(),通知GC運行,但是Java語言規范并不保證GC一定會執行。使用增量式GC可以縮短Java程序的暫停時間。

    參考資料

    文章

    1. 歐陽辰,周欣 "Java與內存泄漏" http://www-900.ibm.com/developerWorks/cn/java/l-JavaMemoryLeak/index.shtml
    2. Y. Srinivas Ramakrishna "Atuomatic Memory Management in the Java HotSpot Virtual Machine",此文章JavaOne2002的演講材料, http://java.sun.com/javaone
    3. Monica Pawlan "Reference Objects and Garbage Collector" 此文章為JDC的文章,可在http://developer.java.sun.com/上找到
    4. Bill Venners Chapter 9 of "Inside the Java 2 Virtual Machine" http://www.artima.com/insidejvm/ed2/ch09GarbageCollectionPrint.html
    5. Sun Microsystems, "Java Language Specification, Second Version"

    關于作者
    歐陽辰,北京大學計算機碩士畢業,98年起開始研究基于java的軟件開發、測試,參與開發、測試過多個基于Java的應用程序和Web服務項目。聯系方式yeekee@sina.com
    周欣,北京大學計算機系在讀博士生,主要研究方向:程序理解、逆向工程及軟件度量,聯系方式 zhouxin@sei.pku.edu.cn


    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=281108

    posted on 2007-06-19 11:22 SIMONE 閱讀(377) 評論(0)  編輯  收藏 所屬分類: JAVAJSP
    主站蜘蛛池模板: 亚洲欧洲免费视频| 久久精品成人免费网站| 一级毛片aaaaaa视频免费看| 四虎影视永久在线精品免费 | 亚洲热线99精品视频| 久久亚洲精品成人| 国产精品亚洲专区在线观看 | 国产精品免费久久久久影院| 国产免费AV片在线观看| 7723日本高清完整版免费| 国产成人免费手机在线观看视频| 国产亚洲视频在线播放| 亚洲天天做日日做天天看| 在线观看亚洲AV每日更新无码| 添bbb免费观看高清视频| 免费观看91视频| 妞干网免费视频观看| 亚洲欧洲自拍拍偷精品 美利坚 | 亚洲AV乱码久久精品蜜桃| 亚洲婷婷第一狠人综合精品| 男女猛烈xx00免费视频试看| 在线人成免费视频69国产| 成人奭片免费观看| 怡红院亚洲怡红院首页| 亚洲国产高清美女在线观看| 男男gay做爽爽的视频免费| 99视频在线看观免费| 国产区卡一卡二卡三乱码免费| 亚洲av伊人久久综合密臀性色| 亚洲国产精品网站在线播放| 最新久久免费视频| 热99re久久免费视精品频软件| 亚洲成色WWW久久网站| 亚洲欧美成人一区二区三区| 两性色午夜免费视频| 最近高清国语中文在线观看免费| 亚洲男人的天堂www| 亚洲综合欧美色五月俺也去| 国产麻豆一精品一AV一免费| 国产免费av片在线无码免费看| 久久久久亚洲精品无码蜜桃|