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

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

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

    道非道 非常道

    勤思、謹(jǐn)言、慎行、厚積、薄發(fā)

    統(tǒng)計(jì)

    web

    天圓

    經(jīng)濟(jì) 政治 軍事

    鍵康

    垃圾回收工作機(jī)制 學(xué)習(xí)自《Java程序員 上班那點(diǎn)事兒》

    4.5 內(nèi)存垃圾回收問(wèn)題

    那本譚浩強(qiáng)主編的Java入門(mén)教材說(shuō):

    ……

    1、簡(jiǎn)單性

    設(shè)計(jì)Java語(yǔ)言的出發(fā)點(diǎn)就是容易編程,不需要深?yuàn)W的知識(shí)。Java語(yǔ)言的風(fēng)格十分接近C++語(yǔ)言,但要比C++簡(jiǎn)單得多。Java舍棄了一些不常用的、難以理解的、容易混淆的成分,如運(yùn)算符重載、多繼承等。增加了自動(dòng)垃圾搜集功能,用于回收不再使用的內(nèi)存區(qū)域。這不但使程序易于編寫(xiě),而且大大減少了由于內(nèi)存分配而引發(fā)的問(wèn)題。

    ……

    這樣類似的描述出現(xiàn)在眾多的Java入門(mén)級(jí)教材中,非常容易讓人們忽略了內(nèi)存垃圾回收的問(wèn)題,其實(shí)Java的垃圾回收問(wèn)還是需要關(guān)注一下的。這個(gè)問(wèn)題在招聘單位的筆試題中出現(xiàn)的頻率也比較高,我們需要好好的研究一下Java的垃圾回收機(jī)制。

    4.5.1 什么是內(nèi)存垃圾,哪些內(nèi)存符合垃圾的標(biāo)準(zhǔn)

    我們?cè)谇懊嬷v過(guò)了,堆是一個(gè)"運(yùn)行時(shí)"數(shù)據(jù)區(qū),是通過(guò)"new"等指令建立的,Java的堆是由Java的垃圾回收機(jī)制來(lái)負(fù)責(zé)處理的,堆是動(dòng)態(tài)分配內(nèi)存大小,垃圾收集器可以自動(dòng)回收不再使用的內(nèi)存空間。

    也就是說(shuō),所謂的"內(nèi)存垃圾"是指在堆上開(kāi)辟的內(nèi)存空間在不用的時(shí)候就變成了"垃圾"。

    C++或其他程序設(shè)計(jì)語(yǔ)言中,必須由程序員自行聲明產(chǎn)生和回收,否則其中的資源將消耗,造成資源的浪費(fèi)甚至死機(jī)。但手工回收內(nèi)存往往是一項(xiàng)復(fù)雜而艱巨的工作。因?yàn)橐A(yù)先確定占用的內(nèi)存空間是否應(yīng)該被回收是非常困難的!如果一段程序不能回收內(nèi)存空間,而且在程序運(yùn)行時(shí)系統(tǒng)中又沒(méi)有了可以分配的內(nèi)存空間時(shí),這段程序就只能崩潰。

    Java和C++相比的優(yōu)勢(shì)在于,這部分"垃圾"可以被Java 虛擬機(jī)(JVM)中的一個(gè)程序發(fā)現(xiàn)并自動(dòng)清除掉,而不用程序員自己想著"delete"了。

    Java語(yǔ)言提供了一個(gè)系統(tǒng)級(jí)的線程,即垃圾收集器線程(Garbage Collection Thread),來(lái)跟蹤每一塊分配出去的內(nèi)存空間,當(dāng)JVM處于空閑循環(huán)時(shí),自動(dòng)回收每一塊可以回收的內(nèi)存。

    4.5.1.1 垃圾回收工作機(jī)制

    垃圾收集器線程它是一種低優(yōu)先級(jí)的線程,它必須在一個(gè)Java程序的運(yùn)行過(guò)程中出現(xiàn)內(nèi)存空閑的時(shí)候才去進(jìn)行回收處理。

    垃圾收集器系統(tǒng)有其判斷內(nèi)存塊是否需要回收的判斷標(biāo)準(zhǔn)的。垃圾收集器完全是自動(dòng)被執(zhí)行的,它不能被強(qiáng)制執(zhí)行,即使程序員能明確地判斷出某一塊內(nèi)存應(yīng)該被回收了,也不能強(qiáng)制執(zhí)行垃圾回收程序進(jìn)行垃圾回收。

    程序員可以做的只有調(diào)用"System.gc()"來(lái)"建議"執(zhí)行垃圾收集器程序,但是這個(gè)垃圾收集程序什么時(shí)候被執(zhí)行以及是否被執(zhí)行了,都是不不能控制的。但是雖然垃圾收集器是低優(yōu)先級(jí)的線程,卻在系統(tǒng)內(nèi)存可用量過(guò)低時(shí),它仍然可能會(huì)突發(fā)地執(zhí)行來(lái)挽救系統(tǒng)。

    4.5.1.2 哪些符合"垃圾"標(biāo)準(zhǔn)

    如果想了解JVM的垃圾回收,就必須要知道JVM垃圾回收的標(biāo)準(zhǔn)。

    垃圾收集器的"垃圾"標(biāo)準(zhǔn):對(duì)象已經(jīng)不能被程序中的其他程序所引用的時(shí)候,那么這個(gè)對(duì)象的內(nèi)存空間已經(jīng)沒(méi)有用了。

    比如當(dāng)一個(gè)方法執(zhí)行完畢時(shí),在這個(gè)方法中聲明的對(duì)象就超出其聲明周期,這時(shí)候就可以被當(dāng)作垃圾收集了,只有當(dāng)這個(gè)方法被再次被調(diào)用時(shí)才會(huì)被重新創(chuàng)建。

    例如:

    ……
    public void function(){
    OBJ obj=new OBJ();
    ……
    }
    ……

    另外還可以將對(duì)象的引用變量初始化為null值,也可以來(lái)暗示垃圾收集器來(lái)收集該對(duì)象。

    例如:

    ……
    OBJ obj=new OBJ();
    Obj=null;
    ……

    finalize()在該對(duì)象垃圾回收前調(diào)用

    垃圾收集器跟蹤每一個(gè)對(duì)象,把那些不可到達(dá)的對(duì)象占有的內(nèi)存空間收集起來(lái),并且在每次進(jìn)行垃圾收集之前,垃圾收集器都會(huì)調(diào)用一下finalize()方法。Java語(yǔ)言允許程序員給任何對(duì)象添加finalize( )方法,但也不能過(guò)分依賴該方法對(duì)系統(tǒng)資源的回收和再利用,因?yàn)檫@個(gè)方法調(diào)用后的執(zhí)行結(jié)果是不可預(yù)知的。對(duì)于任何給定對(duì)象,Java 虛擬機(jī)最多只調(diào)用一次 finalize 方法。

    我們用這個(gè)程序來(lái)演示一下:

    public class finalizeTest{
    public static void main( String[] args ){
     finalizeTest ft=new finalizeTest();
     ft.loading();
     byte bs[]=new byte[1450000];
    }
    public void loading(){
     test t=new test();
     t.callme();
    }
    }
    class test{
    protected void finalize(){
    System.out.println("call finalize");
    }
    public void callme(){
    System.out.println("callme");
    }
    }
    我們?cè)诿钚兄墟I入如下命令:
    java -Xmx1k finalizeTest
    程序運(yùn)行結(jié)果如圖 3 10所示。
                                          

    這時(shí)候,我們將JVM所許可使用的最大內(nèi)存設(shè)置成"1k",當(dāng)內(nèi)存被占滿前JVM會(huì)首先去進(jìn)行內(nèi)存回收,于是失去活動(dòng)的"test"對(duì)象被回收,在回收前調(diào)用了"finalize()"。

    4.5.2 JVM垃圾回收的相關(guān)知識(shí)

    JVM使用的是分代垃圾回收的方式,主要是因?yàn)樵诔绦蜻\(yùn)行的時(shí)候會(huì)有如下特點(diǎn):

    大多數(shù)對(duì)象在創(chuàng)建后很快就沒(méi)有對(duì)象使用它了。

    大多數(shù)在一直被使用的對(duì)象很少再去引用新創(chuàng)建的對(duì)象。

    因此就將Java對(duì)象分為"年輕"對(duì)象和"年老"對(duì)象,JVM將內(nèi)存堆(Heap)分為兩個(gè)區(qū)域,一個(gè)是"年輕"區(qū),另一個(gè)是"老"區(qū),Java將這兩個(gè)區(qū)域分別稱作是"新生代"和"老生代"。

    "新生代"區(qū)域中,絕大多數(shù)新創(chuàng)建的對(duì)象都存放在這個(gè)區(qū)域里,此區(qū)域一般來(lái)說(shuō)較小而且垃圾回收頻率較高,同時(shí)因?yàn)?新生代"采用的算法和其存放的對(duì)象的特點(diǎn),使該區(qū)域垃圾回收的效率也非常高。

    而"老生代"區(qū)域中存放的是在"新生代"中生存了較長(zhǎng)時(shí)間的對(duì)象,這些對(duì)象將被轉(zhuǎn)移到"老生代"區(qū)。這個(gè)區(qū)域一般要大一些而且增長(zhǎng)的速度相對(duì)于"新生代"要慢一些,"老生代"垃圾回收的執(zhí)行頻率也會(huì)低很多。

    由于JVM在垃圾回收處理時(shí)會(huì)消耗一定的系統(tǒng)資源,因此有時(shí)候通過(guò)JVM啟動(dòng)的時(shí)候添加相關(guān)參數(shù)來(lái)控制"新生代"區(qū)域的大小,來(lái)調(diào)整垃圾回收處理的頻率非常有用。以便于我們更合理的利用系統(tǒng)資源。

    "新生代"區(qū)域設(shè)置參數(shù)是"-Xmn",用這個(gè)參數(shù)可以制定"新生代"區(qū)域的大小。

    我們來(lái)舉一個(gè)例子說(shuō)明:

    我們就用系統(tǒng)自帶的程序作為例子,在命令行上鍵入如下指令:

    CD C:"java"demo"jfc"SwingSet2[回車]
    C:"java"demo"jfc"SwingSet2>java -jar -verbose:gc
    -Xmn4m XX:+PrintGCDetails SwingSet2.jar[回車]
    上面加入了一個(gè)新的參數(shù)"XX:+PrintGCDetails",這個(gè)參數(shù)能夠打印出GC的詳細(xì)信息。屏幕輸出如下(節(jié)選):
    [GC [DefNew: 3469K->84K(3712K), 0.0007778 secs] 
    23035K->19679K(28728K), 0.0009191 secs]
    [GC [DefNew: 3284K->171K(3712K), 0.0007283 secs]
    22878K->19766K(28728K), 0.0008669 secs]
    [GC [DefNew: 3476K->260K(3712K), 0.0008504 secs]
    23071K->19855K(28728K), 0.0009862 secs]
    [GC [DefNew: 3502K->87K(3712K), 0.0009267 secs]
    23096K->19682K(28728K), 0.0010610 secs]

    我們需要解釋一下輸出的詳細(xì)內(nèi)容的意思,拿第一行輸出來(lái)說(shuō):

    "DefNew: 3469K->84K(3712K), 0.0007778 secs"是指"新生代"的垃圾回收情況,這里的意思是從占用3469K內(nèi)存空間變?yōu)?4K內(nèi)存空間,用時(shí)0.0007778秒。

    "23035K->19679K(28728K), 0.0009191 secs"是指總體GC的回收情況,整體堆空間占用從23035K降低到19679K的水平,用時(shí)0.0009191秒。

    那么,這時(shí)候我們?cè)趯?新生代"的內(nèi)存設(shè)為8M,并把堆的最大可控值設(shè)定為32M,再去執(zhí)行,鍵入如下指令:

    java -jar -verbose:gc -Xmn8m -Xmx32m 
    XX:+PrintGCDetails SwingSet2.jar[回車]
    得到的結(jié)果如下(節(jié)選):
    [GC [DefNew: 6633K->6633K(7424K), 0.0000684 secs]
    [Tenured: 18740K->18820K(24576K), 0.0636505 secs]
    25374K->18820K(32000K), 0.0639274 secs]
    [GC [DefNew: 6646K->6646K(7424K), 0.0002581 secs]
    [Tenured: 18820K->18884K(24576K), 0.0651957 secs]
    25467K->18884K(32000K), 0.0658804 secs]
    [GC [DefNew: 6611K->6611K(7424K), 0.0000668 secs]
    [Tenured: 18884K->18505K(24576K), 0.0931406 secs]
    25496K->18505K(32000K), 0.0934295 secs]

    這個(gè)結(jié)果說(shuō)明:

    "[DefNew: 6633K->6633K(7424K), 0.0000684 secs]"是指"新生代"的垃圾回收情況,這里的意思是從占用6633K內(nèi)存空間變?yōu)?633K內(nèi)存空間,用時(shí)0. 0000684秒。
    "25374K->18820K(32000K), 0.0639274 secs"是指總體GC的回收情況,整體堆空間占用從25374K降低到18820K的水平,用時(shí)0. 0639274秒。
    "[Tenured: 18740K->18820K(24576K), 0.0636505 secs]"是指"老生代"GC的回收情況,整體堆空間占用從18740K降低到18820K的水平,用時(shí)0.0009012秒。

    通過(guò)這些參數(shù)的調(diào)整我們可以看到在處理垃圾收集問(wèn)題時(shí),從垃圾回收的頻率是時(shí)間方面的變化,我們可以根據(jù)不同程序的不同情況予以調(diào)整。

    最后有必要提一下GC的相關(guān)參數(shù):

    -XX:+PrintGCDetails 顯示GC的詳細(xì)信息
    -XX:+PrintGCApplicationConcurrentTime 打印應(yīng)用執(zhí)行的時(shí)間
    -XX:+PrintGCApplicationStoppedTime 打印應(yīng)用被暫停的時(shí)間
    注:":"后的"+"號(hào)表示開(kāi)啟此選項(xiàng),如果是"-"號(hào)那么表示關(guān)閉此選項(xiàng)。

     

    posted on 2009-07-07 13:23 星期五 閱讀(376) 評(píng)論(0)  編輯  收藏 所屬分類: JAVA SE

    主站蜘蛛池模板: 亚洲黑人嫩小videos| 国产无遮挡无码视频免费软件 | 亚洲精品福利你懂| 国产成人A亚洲精V品无码| 在线免费不卡视频| 99热在线观看免费| 四虎影视无码永久免费| 天堂亚洲免费视频| 亚洲狠狠色丁香婷婷综合| 亚洲国产成人精品无码区在线秒播| 337p日本欧洲亚洲大胆裸体艺术| 免费国产成人午夜私人影视| 无码精品A∨在线观看免费| 久久er国产精品免费观看2| 波霸在线精品视频免费观看| 特级毛片全部免费播放a一级 | 免费的一级黄色片| 欧美a级在线现免费观看| 亚洲一区二区三区免费在线观看 | 亚洲国产成人精品女人久久久 | 亚洲AV成人无码网站| 亚洲久悠悠色悠在线播放| 亚洲沟沟美女亚洲沟沟| 亚洲美女自拍视频| 久久精品国产精品亚洲毛片| 亚洲自偷自拍另类12p| 亚洲视频在线观看一区| 亚洲伊人tv综合网色| 亚洲综合激情另类小说区| 亚洲精品视频在线免费| 亚洲国产精品网站久久| 久久久亚洲AV波多野结衣| 日韩亚洲Av人人夜夜澡人人爽| 亚洲狠狠久久综合一区77777| 亚洲国产人成网站在线电影动漫| 久久精品国产亚洲av麻| 亚洲情a成黄在线观看动漫尤物| 亚洲综合在线观看视频| 亚洲国产品综合人成综合网站| 亚洲国产成人精品电影| 亚洲av成人一区二区三区|