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

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

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

    posts - 9, comments - 4, trackbacks - 0, articles - 21
    1.垃圾收集算法的核心思想

      Java語言建立了垃圾收集機(jī)制,用以跟蹤正在使用的對象和發(fā)現(xiàn)并回收不再使用(引用)的對象。該機(jī)制可以有效防范動態(tài)內(nèi)存分配中可能發(fā)生的兩個危險:因內(nèi)存垃圾過多而引發(fā)的內(nèi)存耗盡,以及不恰當(dāng)?shù)膬?nèi)存釋放所造成的內(nèi)存非法引用。

      垃圾收集算法的核心思想是:對虛擬機(jī)可用內(nèi)存空間,即堆空間中的對象進(jìn)行識別,如果對象正在被引用,那么稱其為存活對象,反之,如果對象不再被 引用,則為垃圾對象,可以回收其占據(jù)的空間,用于再分配。垃圾收集算法的選擇和垃圾收集系統(tǒng)參數(shù)的合理調(diào)節(jié)直接影響著系統(tǒng)性能,因此需要開發(fā)人員做比較深 入的了解。

      2.觸發(fā)主GC(Garbage Collector)的條件

      JVM進(jìn)行次GC的頻率很高,但因為這種GC占用時間極短,所以對系統(tǒng)產(chǎn)生的影響不大。更值得關(guān)注的是主GC的觸發(fā)條件,因為它對系統(tǒng)影響很明顯。總的來說,有兩個條件會觸發(fā)主GC:

      ①當(dāng)應(yīng)用程序空閑時,即沒有應(yīng)用線程在運(yùn)行時,GC會被調(diào)用。因為GC在優(yōu)先級最低的線程中進(jìn)行,所以當(dāng)應(yīng)用忙時,GC線程就不會被調(diào)用,但以下條件除外。

      ②Java堆內(nèi)存不足時,GC會被調(diào)用。當(dāng)應(yīng)用線程在運(yùn)行,并在運(yùn)行過程中創(chuàng)建新對象,若這時內(nèi)存空間不足,JVM就會強(qiáng)制地調(diào)用GC線程,以 便回收內(nèi)存用于新的分配。若GC一次之后仍不能滿足內(nèi)存分配的要求,JVM會再進(jìn)行兩次GC作進(jìn)一步的嘗試,若仍無法滿足要求,則 JVM將報“out of memory”的錯誤,Java應(yīng)用將停止。

      由于是否進(jìn)行主GC由JVM根據(jù)系統(tǒng)環(huán)境決定,而系統(tǒng)環(huán)境在不斷的變化當(dāng)中,所以主GC的運(yùn)行具有不確定性,無法預(yù)計它何時必然出現(xiàn),但可以確定的是對一個長期運(yùn)行的應(yīng)用來說,其主GC是反復(fù)進(jìn)行的。

      3.減少GC開銷的措施

      根據(jù)上述GC的機(jī)制,程序的運(yùn)行會直接影響系統(tǒng)環(huán)境的變化,從而影響GC的觸發(fā)。若不針對GC的特點進(jìn)行設(shè)計和編碼,就會出現(xiàn)內(nèi)存駐留等一系列負(fù)面影響。為了避免這些影響,基本的原則就是盡可能地減少垃圾和減少GC過程中的開銷。具體措施包括以下幾個方面:

      (1)不要顯式調(diào)用System.gc()

      此函數(shù)建議JVM進(jìn)行主GC,雖然只是建議而非一定,但很多情況下它會觸發(fā)主GC,從而增加主GC的頻率,也即增加了間歇性停頓的次數(shù)。

      (2)盡量減少臨時對象的使用

      臨時對象在跳出函數(shù)調(diào)用后,會成為垃圾,少用臨時變量就相當(dāng)于減少了垃圾的產(chǎn)生,從而延長了出現(xiàn)上述第二個觸發(fā)條件出現(xiàn)的時間,減少了主GC的機(jī)會。

      (3)對象不用時最好顯式置為Null

      一般而言,為Null的對象都會被作為垃圾處理,所以將不用的對象顯式地設(shè)為Null,有利于GC收集器判定垃圾,從而提高了GC的效率。

      (4)盡量使用StringBuffer,而不用String來累加字符串(詳見blog另一篇文章JAVA中String與StringBuffer)

      由于String是固定長的字符串對象,累加String對象時,并非在一個String對象中擴(kuò)增,而是重新創(chuàng)建新的String對象,如 Str5=Str1+Str2+Str3+Str4,這條語句執(zhí)行過程中會產(chǎn)生多個垃圾對象,因為對次作“+”操作時都必須創(chuàng)建新的String對象,但 這些過渡對象對系統(tǒng)來說是沒有實際意義的,只會增加更多的垃圾。避免這種情況可以改用StringBuffer來累加字符串,因StringBuffer 是可變長的,它在原有基礎(chǔ)上進(jìn)行擴(kuò)增,不會產(chǎn)生中間對象。

      (5)能用基本類型如Int,Long,就不用Integer,Long對象

      基本類型變量占用的內(nèi)存資源比相應(yīng)對象占用的少得多,如果沒有必要,最好使用基本變量。

      (6)盡量少用靜態(tài)對象變量

      靜態(tài)變量屬于全局變量,不會被GC回收,它們會一直占用內(nèi)存。

      (7)分散對象創(chuàng)建或刪除的時間

      集中在短時間內(nèi)大量創(chuàng)建新對象,特別是大對象,會導(dǎo)致突然需要大量內(nèi)存,JVM在面臨這種情況時,只能進(jìn)行主GC,以回收內(nèi)存或整合內(nèi)存碎片, 從而增加主GC的頻率。集中刪除對象,道理也是一樣的。它使得突然出現(xiàn)了大量的垃圾對象,空閑空間必然減少,從而大大增加了下一次創(chuàng)建新對象時強(qiáng)制主GC 的機(jī)會。


    4.gc與finalize方法

      ⑴gc方法請求垃圾回收

      使用System.gc()可以不管JVM使用的是哪一種垃圾回收的算法,都可以請求Java的垃圾回收。需要注意的是,調(diào)用 System.gc()也僅僅是一個請求。JVM接受這個消息后,并不是立即做垃圾回收,而只是對幾個垃圾回收算法做了加權(quán),使垃圾回收操作容易發(fā)生,或 提早發(fā)生,或回收較多而已。

      ⑵finalize方法透視垃圾收集器的運(yùn)行

      在JVM垃圾收集器收集一個對象之前 ,一般要求程序調(diào)用適當(dāng)?shù)姆椒ㄡ尫刨Y源,但在沒有明確釋放資源的情況下,Java提供了缺省機(jī)制來終止化該對象釋放資源,這個方法就是finalize()。它的原型為:

      protected void finalize() throws Throwable

      在finalize()方法返回之后,對象消失,垃圾收集開始執(zhí)行。原型中的throws Throwable表示它可以拋出任何類型的異常。

      因此,當(dāng)對象即將被銷毀時,有時需要做一些善后工作。可以把這些操作寫在finalize()方法里。

    以下是引用片段:
    protected void finalize()
    {
    // finalization code here
    }
    ⑶代碼示例 以下是引用片段:
    class Garbage
    {
    int index;
    static int count;
    Garbage()
    {
    count++;
    System.out.println("object "+count+" construct");
    setID(count);
    }
    void setID(int id)
    {
    index=id;
    }
    protected void finalize() //重寫finalize方法
    {
    System.out.println("object "+index+" is reclaimed");
    }
    public static void main(String[] args)
    {
    new Garbage();
    new Garbage();
    new Garbage();
    new Garbage();
    System.gc(); //請求運(yùn)行垃圾收集器
    }
    }

    5.Java 內(nèi)存泄漏

      由于采用了垃圾回收機(jī)制,任何不可達(dá)對象(對象不再被引用)都可以由垃圾收集線程回收。因此通常說的Java 內(nèi)存泄漏其實是指無意識的、非故意的對象引用,或者無意識的對象保持。無意識的對象引用是指代碼的開發(fā)人員本來已經(jīng)對對象使用完畢,卻因為編碼的錯誤而意 外地保存了對該對象的引用(這個引用的存在并不是編碼人員的主觀意愿),從而使得該對象一直無法被垃圾回收器回收掉,這種本來以為可以釋放掉的卻最終未能 被釋放的空間可以認(rèn)為是被“泄漏了”。

      考慮下面的程序,在ObjStack類中,使用push和pop方法來管理堆棧中的對象。兩個方法中的索引(index)用于指示堆棧中下一個 可用位置。push方法存儲對新對象的引用并增加索引值,而pop方法減小索引值并返回堆棧最上面的元素。在main方法中,創(chuàng)建了容量為64的棧,并 64次調(diào)用push方法向它添加對象,此時index的值為64,隨后又32次調(diào)用pop方法,則index的值變?yōu)?2,出棧意味著在堆棧中的空間應(yīng)該 被收集。但事實上,pop方法只是減小了索引值,堆棧仍然保持著對那些對象的引用。故32個無用對象不會被GC回收,造成了內(nèi)存滲漏。

    以下是引用片段:
    public class ObjStack {
    private Object[] stack;
    private int index;
    ObjStack(int indexcount) {
    stack = new Object[indexcount];
    index = 0;
    }
    public void push(Object obj) {
    stack[index] = obj;
    index++;
    }
    public Object pop() {
    index--;
    return stack[index];
    }
    }
    public class Pushpop {
    public static void main(String[] args) {
    int i = 0;
    Object tempobj;
    ObjStack stack1 = new ObjStack(64);//new一個ObjStack對象,并調(diào)用有參構(gòu)造函數(shù)。分配stack Obj數(shù)組的空間大小為64,可以存64個對象,從0開始存儲。
    while (i < 64)
    {
    tempobj = new Object();//循環(huán)new Obj對象,把每次循環(huán)的對象一一存放在stack Obj數(shù)組中。
    stack1.push(tempobj);
    i++;
    System.out.println("第" + i + "次進(jìn)棧" + ""t");
    }
    while (i > 32)
    {
    tempobj = stack1.pop();//這里造成了空間的浪費。
    //正確的pop方法可改成如下所指示,當(dāng)引用被返回后,堆棧刪除對他們的引用,因此垃圾收集器在以后可以回收他們。
    /*
    * public Object pop() {index - -;Object temp = stack [index];stack [index]=null;return temp;}
    */
    i--;
    System.out.println("第" + (64 - i) + "次出棧" + ""t");
    }
    }
    }

    5.Java 內(nèi)存泄漏

      由于采用了垃圾回收機(jī)制,任何不可達(dá)對象(對象不再被引用)都可以由垃圾收集線程回收。因此通常說的Java 內(nèi)存泄漏其實是指無意識的、非故意的對象引用,或者無意識的對象保持。無意識的對象引用是指代碼的開發(fā)人員本來已經(jīng)對對象使用完畢,卻因為編碼的錯誤而意 外地保存了對該對象的引用(這個引用的存在并不是編碼人員的主觀意愿),從而使得該對象一直無法被垃圾回收器回收掉,這種本來以為可以釋放掉的卻最終未能 被釋放的空間可以認(rèn)為是被“泄漏了”。

      考慮下面的程序,在ObjStack類中,使用push和pop方法來管理堆棧中的對象。兩個方法中的索引(index)用于指示堆棧中下一個 可用位置。push方法存儲對新對象的引用并增加索引值,而pop方法減小索引值并返回堆棧最上面的元素。在main方法中,創(chuàng)建了容量為64的棧,并 64次調(diào)用push方法向它添加對象,此時index的值為64,隨后又32次調(diào)用pop方法,則index的值變?yōu)?2,出棧意味著在堆棧中的空間應(yīng)該 被收集。但事實上,pop方法只是減小了索引值,堆棧仍然保持著對那些對象的引用。故32個無用對象不會被GC回收,造成了內(nèi)存滲漏。

    以下是引用片段:
    public class ObjStack {
    private Object[] stack;
    private int index;
    ObjStack(int indexcount) {
    stack = new Object[indexcount];
    index = 0;
    }
    public void push(Object obj) {
    stack[index] = obj;
    index++;
    }
    public Object pop() {
    index--;
    return stack[index];
    }
    }
    public class Pushpop {
    public static void main(String[] args) {
    int i = 0;
    Object tempobj;
    ObjStack stack1 = new ObjStack(64);//new一個ObjStack對象,并調(diào)用有參構(gòu)造函數(shù)。分配stack Obj數(shù)組的空間大小為64,可以存64個對象,從0開始存儲。
    while (i < 64)
    {
    tempobj = new Object();//循環(huán)new Obj對象,把每次循環(huán)的對象一一存放在stack Obj數(shù)組中。
    stack1.push(tempobj);
    i++;
    System.out.println("第" + i + "次進(jìn)棧" + ""t");
    }
    while (i > 32)
    {
    tempobj = stack1.pop();//這里造成了空間的浪費。
    //正確的pop方法可改成如下所指示,當(dāng)引用被返回后,堆棧刪除對他們的引用,因此垃圾收集器在以后可以回收他們。
    /*
    * public Object pop() {index - -;Object temp = stack [index];stack [index]=null;return temp;}
    */
    i--;
    System.out.println("第" + (64 - i) + "次出棧" + ""t");
    }
    }
    }







    Feedback

    # re: 垃圾清理勢在必行——java垃圾收集算法[未登錄]  回復(fù)  更多評論   

    2010-03-17 15:09 by 李強(qiáng)
    軟引用的實質(zhì)就是緩存

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国产免费久久精品| 久久久久久成人毛片免费看| 青娱乐免费视频在线观看| 亚洲国产精品成人精品无码区在线 | 亚洲人成网站日本片| 182tv免费观看在线视频| 亚洲国产综合精品| 88av免费观看入口在线| 久久亚洲春色中文字幕久久久| 99视频精品全部免费观看| 亚洲视频免费在线播放| 美丽的姑娘免费观看在线播放| 精品亚洲国产成AV人片传媒| 亚洲国产精品免费观看| 亚洲狠狠婷婷综合久久| 国产美女被遭强高潮免费网站| 青娱乐在线免费观看视频| 免费在线观看黄网| 久久毛片免费看一区二区三区| 国产亚洲AV手机在线观看| 麻豆精品成人免费国产片| 久久亚洲精品无码aⅴ大香| 无码一区二区三区AV免费| 亚洲av无码一区二区三区在线播放| 亚洲av中文无码| 免费久久人人爽人人爽av | 日本免费一区二区三区最新vr| 久久精品国产亚洲av瑜伽| 怡红院亚洲怡红院首页| 久久国产乱子伦精品免费不卡| 国产精品亚洲片夜色在线| 国产成人aaa在线视频免费观看| 国产精品免费视频观看拍拍| 亚洲AV成人精品网站在线播放| 国产精品美女午夜爽爽爽免费| 国产成人亚洲毛片| 久久91亚洲精品中文字幕| 在线免费观看毛片网站| 国内精品免费久久影院| 亚洲人配人种jizz| 亚洲欧洲自拍拍偷午夜色无码|