嵌入式系統(tǒng)設(shè)計(jì)中的存儲(chǔ)碎片收集策略
掃描二維碼
隨時(shí)隨地手機(jī)看文章
隨著嵌入式系統(tǒng)數(shù)據(jù)對(duì)象處理量的急劇增加,對(duì)存儲(chǔ)碎片收集的實(shí)時(shí)性能的要求也顯得日益突出,本文介紹的真正高效、實(shí)時(shí)、確定性的兩種存儲(chǔ)碎片收集技術(shù)將對(duì)(中國(guó))工程師提供策略上的指導(dǎo)。
在嵌入式系統(tǒng)設(shè)計(jì)過(guò)程中,Java程序員并不需要弄清楚哪些數(shù)據(jù)占用了哪些存儲(chǔ)器或者應(yīng)該在什么位置釋放哪些存儲(chǔ)空間,設(shè)計(jì)工程師只需要簡(jiǎn)單地分配對(duì)象而后由系統(tǒng)來(lái)釋放這些資源。這樣就可以完全消除懸浮指針錯(cuò)誤,因而極大地減小存儲(chǔ)空間浪費(fèi)的可能性。由于并不需要一些顯式的規(guī)則來(lái)指定這些存儲(chǔ)空間的釋放,因此簡(jiǎn)化了接口并且增強(qiáng)了軟件復(fù)用。自動(dòng)診測(cè)并釋放這些不再使用的對(duì)象的系統(tǒng)進(jìn)程稱為存儲(chǔ)碎片收集(garbage collection)。
假如存儲(chǔ)碎片收集真有這么好,人們也許會(huì)懷疑為什么在ANSI C++中不具備這樣的功能。事實(shí)上,C++語(yǔ)言擴(kuò)充版允許程序員將一些類型指定為“受控對(duì)象類型”,比如在Microsoft Visual C++的.NET平臺(tái)中就能找到這種應(yīng)用。這些受控對(duì)象在一定的條件下,可以實(shí)現(xiàn)自動(dòng)存儲(chǔ)碎片收集。問(wèn)題的關(guān)鍵是存儲(chǔ)碎片收集器必須能夠找到所有的對(duì)象指針。由于C++允許將指針映射為其它類型,所以通常情況下無(wú)法追蹤所有的指針。
關(guān)聯(lián)存儲(chǔ)碎片收集是對(duì)傳統(tǒng)存儲(chǔ)碎片收集算法的一個(gè)重大改進(jìn)。基本的思路就是關(guān)注最新的對(duì)象。這是由于大多數(shù)對(duì)象都是很快產(chǎn)生而又很快消失,這些很快消失的對(duì)象集通常構(gòu)成了絕大部分存儲(chǔ)碎片。當(dāng)然事情遠(yuǎn)比這要復(fù)雜。
彈性清除存儲(chǔ)碎片
基于“標(biāo)示和掃描”方式的傳統(tǒng)存儲(chǔ)碎片收集算法工作過(guò)程如下:當(dāng)存儲(chǔ)空間太低(下降到一個(gè)失效的新值)時(shí),系統(tǒng)就會(huì)停止所有用戶線程,定位無(wú)法訪問(wèn)的對(duì)象集合并且釋放這些對(duì)象。要做到這一點(diǎn)就必須檢查每一個(gè)對(duì)象索引,如從“根”開(kāi)始的局部變量和靜態(tài)類型域。檢查每一個(gè)索引的對(duì)象確定其是否已經(jīng)被標(biāo)記過(guò)。如果沒(méi)有,首先標(biāo)記該對(duì)象并且對(duì)它所有的索引進(jìn)行處理,否則就繼續(xù)處理下一個(gè)索引。這一過(guò)程結(jié)束后,任何未被標(biāo)示的對(duì)象都被認(rèn)為是無(wú)法訪問(wèn)的對(duì)象,因而可以回收再利用其占用的存儲(chǔ)空間。由于這種技術(shù)能夠正確地檢測(cè)被其它消失對(duì)象索引的成組消失對(duì)象,因而要比索引計(jì)數(shù)機(jī)制高明。圖1和圖2分別顯示出這一對(duì)應(yīng)過(guò)程前/后的圖像。
當(dāng)然存儲(chǔ)空間在任何時(shí)候都有可能出現(xiàn)自由空間過(guò)低的情況,并且標(biāo)示和掃描過(guò)程所需要的時(shí)間正比于對(duì)象以及索引的數(shù)量,因而就會(huì)出現(xiàn)應(yīng)用程序可能周期性地出現(xiàn)不響應(yīng)或者滯后短暫的時(shí)間間隔才開(kāi)始響應(yīng)的問(wèn)題。這樣的滯后在實(shí)時(shí)系統(tǒng)甚至是在“軟”實(shí)時(shí)的系統(tǒng)中都是不能接受的。
有的設(shè)計(jì)師試圖使用一種稱為增量式存儲(chǔ)碎片收集(incremental garbage collector)的技術(shù)來(lái)確保這種應(yīng)用的滯后時(shí)間最小。簡(jiǎn)單地說(shuō),就是存儲(chǔ)碎片收集器僅僅在一個(gè)固定的時(shí)間增量上運(yùn)行,運(yùn)行結(jié)束之后交給用戶線程一個(gè)重新執(zhí)行的機(jī)會(huì)。應(yīng)用程序有更多時(shí)間運(yùn)行之后,增量式存儲(chǔ)碎片收集器將從原來(lái)停止的位置處繼續(xù)工作。注意:當(dāng)應(yīng)用程序線程先占了存儲(chǔ)碎片收集器線程后,有的存儲(chǔ)碎片收集器必須從頭開(kāi)始重新運(yùn)行,這樣的存儲(chǔ)碎片收集器就稱為可以被搶先的,但不是增量式的。
可以搶先式以及增量式存儲(chǔ)碎片收集器都聲稱可以減少滯后時(shí)間,但是這些算法效率的差異卻很大。對(duì)搶先式存儲(chǔ)碎片收集器來(lái)說(shuō),如果經(jīng)常被搶先,那么收集器線程永遠(yuǎn)無(wú)法進(jìn)一步執(zhí)行,因而也就沒(méi)有任何的用處。同樣,如果存儲(chǔ)碎片收集只有當(dāng)某一個(gè)應(yīng)用線程極度缺乏存儲(chǔ)空間時(shí)才啟動(dòng)執(zhí)行的話,那么至少該線程(如果不是完整的應(yīng)用程序)必須滯后運(yùn)行,因?yàn)樵摼€程要在存儲(chǔ)碎片收集線程釋放存儲(chǔ)空間之后才能繼續(xù)運(yùn)行。
收集器時(shí)間增量的長(zhǎng)度也稱為等待時(shí)間,它對(duì)于應(yīng)用的響應(yīng)同樣也是十分關(guān)鍵的。取決于應(yīng)用的實(shí)現(xiàn)時(shí)間增量,其范圍大約從幾秒到幾十分之一毫秒。時(shí)間增量越小,應(yīng)用的響應(yīng)就越具有實(shí)時(shí)性。很顯然,在應(yīng)用的響應(yīng)速度與存儲(chǔ)空間收集器的工作能力之間存在一種工程折衷。
一個(gè)去碎片(defragmenting)的存儲(chǔ)碎片收集器可以在存儲(chǔ)器空間各處移動(dòng)有效對(duì)象,并且將閑置的存儲(chǔ)器空間合并成少數(shù)更大的存儲(chǔ)器區(qū)塊。如果不具備這種去碎片的能力,那么可用的存儲(chǔ)器空間將被分隔成許多小的存儲(chǔ)器小塊,因而最終大對(duì)象的存儲(chǔ)空間分配可能失敗(特別是在長(zhǎng)運(yùn)行時(shí)間的程序中)。
由于系統(tǒng)越來(lái)越難找到足夠大的自由存儲(chǔ)器空間以滿足應(yīng)用程序的需要,因此存儲(chǔ)器去碎片也會(huì)導(dǎo)致每一次的存儲(chǔ)空間分配操作要花更長(zhǎng)的時(shí)間。相反,在一個(gè)已經(jīng)去碎片的存儲(chǔ)器空間中,存儲(chǔ)空間的分配要快得多。系統(tǒng)只需要增值一個(gè)自由指針,這并不比為一種功能調(diào)用而分配一個(gè)堆棧結(jié)構(gòu)更困難。
去碎片存儲(chǔ)碎片收集器通常將存儲(chǔ)空間分為幾個(gè)區(qū)域。一個(gè)區(qū)域的存儲(chǔ)碎片收集完成之后,通常將該區(qū)域中的有效對(duì)象集中到其它區(qū)域中去。這一過(guò)程結(jié)束后,原來(lái)的區(qū)域會(huì)被清空,而且目標(biāo)區(qū)域中也不存在任何間隙。當(dāng)然這還需要附加存儲(chǔ)器,然后才能消除存儲(chǔ)器碎片。
關(guān)聯(lián)存儲(chǔ)碎片收集
關(guān)聯(lián)存儲(chǔ)碎片收集(generational garbage collection)的工作方式如下:許多存儲(chǔ)器區(qū)域被指定為存放新產(chǎn)生對(duì)象的特殊場(chǎng)所。當(dāng)這些對(duì)象存在的時(shí)間變長(zhǎng)(存活的時(shí)間變長(zhǎng),在存儲(chǔ)碎片收集期間依然存活),就會(huì)將它們從這一特殊區(qū)域轉(zhuǎn)移出去并且放到主存儲(chǔ)區(qū)域。某些關(guān)聯(lián)存儲(chǔ)碎片收集算法甚至還區(qū)分幾個(gè)“較早的”代。.NET平臺(tái)以及C#語(yǔ)言的存儲(chǔ)碎片收集器可以區(qū)分三代,所以可以將第一代與存放新產(chǎn)生對(duì)象的區(qū)域分別開(kāi)來(lái)。為了簡(jiǎn)單起見(jiàn),介紹僅有兩代的情況,多代的算法與此相似,只是管理操作方面的運(yùn)算更多。
關(guān)聯(lián)存儲(chǔ)碎片收集僅僅考慮新產(chǎn)生對(duì)象存儲(chǔ)區(qū)域,從本質(zhì)上來(lái)說(shuō),它假定所有駐留在非新產(chǎn)生對(duì)象存儲(chǔ)區(qū)域的對(duì)象仍然在被引用(也就是說(shuō)它們?nèi)匀皇怯行У?。要做到這一點(diǎn),就需要有一種方法來(lái)計(jì)算所有索引了新產(chǎn)生對(duì)象的集合。為了加速這一過(guò)程,需要維護(hù)一個(gè)獨(dú)立的“老對(duì)象到新產(chǎn)生對(duì)象的索引”表,這一索引表列出了所有非新產(chǎn)生對(duì)象對(duì)于新產(chǎn)生對(duì)象的索引。這一表格極大地加速了新產(chǎn)生對(duì)象存儲(chǔ)區(qū)域?qū)ο蟮臋z查,與此同時(shí)非新產(chǎn)生對(duì)象則根本不需要檢查。
也許有人會(huì)關(guān)心:開(kāi)始的時(shí)候如何追蹤非新產(chǎn)生對(duì)象對(duì)新產(chǎn)生對(duì)象的索引?答案在于一種稱為“寫屏蔽”技術(shù)。寫屏蔽監(jiān)視所有的存儲(chǔ)操作,并且不斷查詢“正在存儲(chǔ)的對(duì)象索引了非新產(chǎn)生的對(duì)象嗎”?如果是這樣,接下來(lái)就會(huì)詢問(wèn)是否將正在被寫的舊值以及/或正在被存儲(chǔ)的新值進(jìn)行了索引,并產(chǎn)生了新的對(duì)象。此外,還要對(duì)這一組老對(duì)象到新產(chǎn)生對(duì)象的索引進(jìn)行相關(guān)的刷新。請(qǐng)注意:通過(guò)比較索引的地址與新產(chǎn)生對(duì)象存儲(chǔ)區(qū)域的邊界地址,存儲(chǔ)碎片收集器可以迅速地判定一個(gè)索引是否指向了一個(gè)新產(chǎn)生的對(duì)象。
典型應(yīng)用的實(shí)際測(cè)試表明:老對(duì)象到新產(chǎn)生對(duì)象的索引集合通常都比較小。測(cè)試也證實(shí)關(guān)聯(lián)存儲(chǔ)碎片收集可以線性地分配空間收集工作。也就是說(shuō),關(guān)聯(lián)存儲(chǔ)碎片收集在大約八分之一全部存儲(chǔ)碎片收集的時(shí)間里可以收集到最新的第八個(gè)存儲(chǔ)器空間。這將釋放比八分之一存儲(chǔ)碎片要多得多的空間。
圖3顯示了存儲(chǔ)碎片收集之前的一種情況。新產(chǎn)生對(duì)象存儲(chǔ)空間包含三個(gè)對(duì)象:C、D和E。對(duì)象C包含到對(duì)象E的索引。主要存儲(chǔ)器區(qū)域包含兩個(gè)對(duì)象:A和B。對(duì)象A包含到對(duì)象C的索引。這一個(gè)索引被記錄在“老對(duì)象到新產(chǎn)生對(duì)象”的集合中。根索引集合包含到A和E的索引。
這個(gè)實(shí)例顯示了對(duì)新產(chǎn)生對(duì)象存儲(chǔ)區(qū)域同時(shí)進(jìn)行存儲(chǔ)碎片收集和去碎片的情況。同時(shí)也顯示了對(duì)新產(chǎn)生對(duì)象存儲(chǔ)區(qū)域進(jìn)行存儲(chǔ)碎片收集并且直接收集到主存儲(chǔ)空間中的情況。這樣可以提升新產(chǎn)生對(duì)象存儲(chǔ)區(qū)域中的所有對(duì)象。也就是說(shuō),這些對(duì)象下一輪的關(guān)聯(lián)存儲(chǔ)碎片收集過(guò)程中將不再被檢查。如果算法支持幾代關(guān)聯(lián)存儲(chǔ)碎片收集過(guò)程,那么就需要通過(guò)存儲(chǔ)器去碎片技術(shù)整合到一個(gè)區(qū)域并且進(jìn)行更高一代關(guān)聯(lián)存儲(chǔ)碎片收集。
在關(guān)聯(lián)存儲(chǔ)碎片收集過(guò)程中,根到A的索引將被忽略,但是根到E的索引將把E標(biāo)示為有效,所以在目標(biāo)區(qū)域中會(huì)創(chuàng)建E的一個(gè)副本,并且刷新C到E的索引。
E不包括任何索引,因而對(duì)E不作任何處理。老對(duì)象到新產(chǎn)生對(duì)象的集合也需要檢查,在檢查中會(huì)發(fā)現(xiàn)A到C的索引。C會(huì)被標(biāo)示為有效,所以在目標(biāo)區(qū)域中就會(huì)創(chuàng)建C的一個(gè)副本,并且刷新從A到C的索引。對(duì)象C包含一個(gè)到E的索引。由于E已經(jīng)被復(fù)制,C中的索引被刷新,但是無(wú)需再?gòu)?fù)制E。而無(wú)法訪問(wèn)的對(duì)象D則不會(huì)被復(fù)制,因此該區(qū)域重新整理時(shí)D就會(huì)被刪除。這樣就會(huì)產(chǎn)生圖4中顯示出的結(jié)果。
增量式存儲(chǔ)碎片收集
增量式存儲(chǔ)碎片收集(incremental garbage collection)比關(guān)聯(lián)存儲(chǔ)碎片收集更加復(fù)雜。盡管現(xiàn)在有幾種不同的實(shí)現(xiàn)方式都聲稱是增量式存儲(chǔ)碎片收集,但事實(shí)上這是多年來(lái)懸而未決的問(wèn)題。下面描述增量式存儲(chǔ)碎片收集的一種特定的實(shí)現(xiàn)方式。
考慮在“來(lái)源”和“目的”區(qū)域上運(yùn)行的一個(gè)去碎片存儲(chǔ)碎片收集器(關(guān)聯(lián)型或者非關(guān)聯(lián)型)。隨著存儲(chǔ)碎片收集的進(jìn)行,“來(lái)源”區(qū)域中的全部有效對(duì)象都會(huì)移到“目的”區(qū)域。復(fù)制過(guò)程由索引遍歷來(lái)驅(qū)動(dòng)。每一個(gè)索引都采取以下的處理方式:如果目標(biāo)對(duì)象還沒(méi)有被復(fù)制,那么就復(fù)制該目標(biāo)對(duì)象,并且將其索引添加到要處理的索引列表中。最初的索引都要重新改寫以反映對(duì)象的新位置,并且指向目標(biāo)對(duì)象新位置的一個(gè)前向地址會(huì)保留在那個(gè)對(duì)象最初的“來(lái)源位置”處。當(dāng)所有索引的對(duì)象都已經(jīng)被復(fù)制,并且所有的索引都已經(jīng)重新改寫,那么存儲(chǔ)碎片收集(那一個(gè)區(qū)域的)就結(jié)束,并且“來(lái)源”區(qū)域可以重新使用。
增量式存儲(chǔ)碎片收集通常采取突發(fā)、短時(shí)運(yùn)行方式。在這些突發(fā)的運(yùn)行之間,允許用戶線程運(yùn)行,這樣就可以減少等待時(shí)間。當(dāng)然,在用戶線程執(zhí)行之前,存儲(chǔ)碎片收集器并不能夠保證對(duì)一個(gè)對(duì)象的所有索引都進(jìn)行合適的重新改寫。那么當(dāng)索引僅僅修正了一半的時(shí)候,程序怎樣才能準(zhǔn)確無(wú)誤地繼續(xù)運(yùn)行?答案同樣也在于寫屏蔽。
當(dāng)程序試圖對(duì)存儲(chǔ)器進(jìn)行寫操作時(shí),系統(tǒng)會(huì)進(jìn)行檢查,以確保被寫入的對(duì)象是否正在被存儲(chǔ)碎片收集器移走。如果是這樣,那么寫操作就會(huì)在舊的位置和新的位置同時(shí)進(jìn)行。這樣的技術(shù)避免了“讀屏蔽”的必要性,同時(shí)也保證借助于沒(méi)有被修正的索引,所作的修改不會(huì)被丟失。
聰明的讀者會(huì)注意到:對(duì)象索引的集合在突發(fā)的存儲(chǔ)碎片收集之間可能會(huì)改變。去掉索引應(yīng)該沒(méi)有什么壞處。存儲(chǔ)碎片收集器已經(jīng)標(biāo)示出:一個(gè)對(duì)象是有效對(duì)象移去之后這個(gè)對(duì)象最后的索引,那么該對(duì)象肯定可以在下一次的存儲(chǔ)碎片收集過(guò)程中收集起來(lái)。
然而必須小心處理索引的增加。存儲(chǔ)碎片收集進(jìn)程“正在處理”的過(guò)程中,每一次存儲(chǔ)一個(gè)新的索引時(shí),當(dāng)存儲(chǔ)碎片收集繼續(xù)執(zhí)行時(shí),必須將該索引添加到需要處理的索引列表中。同樣寫屏蔽也要確保這一過(guò)程將工作正常。
在增量式存儲(chǔ)碎片收集過(guò)程中,關(guān)于新對(duì)象的創(chuàng)建也有其它巧妙的細(xì)節(jié)。這些對(duì)象必須小心地分配在一個(gè)獨(dú)立的區(qū)域中,存儲(chǔ)碎片收集結(jié)束后,該區(qū)域?qū)⒊蔀樾庐a(chǎn)生對(duì)象的存儲(chǔ)區(qū)域。如果能讓這些新對(duì)象立即參與當(dāng)前的存儲(chǔ)碎片收集過(guò)程,那么它們就可以迅速升級(jí)。而采用其它方法,它們則會(huì)錯(cuò)過(guò)最開(kāi)始的機(jī)會(huì),并且沒(méi)有機(jī)會(huì)存儲(chǔ)在新產(chǎn)生對(duì)象的存儲(chǔ)空間中,并通過(guò)關(guān)聯(lián)存儲(chǔ)碎片收集器來(lái)進(jìn)行快速收集。
新的問(wèn)題
通過(guò)上面所有的討論,存儲(chǔ)碎片收集聽(tīng)上去比實(shí)際情況更直觀。系統(tǒng)執(zhí)行應(yīng)用程序代碼需要花費(fèi)的時(shí)間總量,以及執(zhí)行存儲(chǔ)碎片收集的時(shí)間總量之間存在某種精細(xì)的平衡。如果系統(tǒng)需要花費(fèi)太多的時(shí)間去實(shí)施存儲(chǔ)碎片收集,那么數(shù)據(jù)吞吐量就會(huì)受到影響。如果系統(tǒng)花費(fèi)太多的時(shí)間去執(zhí)行應(yīng)用程序代碼,那么存儲(chǔ)碎片收集器就不能進(jìn)一步運(yùn)行下去,最終導(dǎo)致應(yīng)用程序必須等待完整的存儲(chǔ)碎片收集完成,所以最壞情況下,滯后問(wèn)題可能得不到解決,當(dāng)然這種情況極為稀少。
由于存儲(chǔ)碎片收集器上的負(fù)載隨應(yīng)用行為而變化,因此僅僅調(diào)節(jié)存儲(chǔ)碎片收集的靜態(tài)參數(shù)不太可能達(dá)到較好的平衡。要切實(shí)解決這一問(wèn)題,存儲(chǔ)碎片收集子系統(tǒng)需要?jiǎng)討B(tài)地監(jiān)視其自身與應(yīng)用的相對(duì)情況。應(yīng)用分配了多少存儲(chǔ)器?存儲(chǔ)器從新產(chǎn)生對(duì)象存儲(chǔ)區(qū)域到主要存儲(chǔ)區(qū)域之間的升級(jí)有多快?存儲(chǔ)碎片收集正在順利進(jìn)行還是已經(jīng)滯后?如果已經(jīng)滯后,那么應(yīng)該怎么辦?需要更加頻繁地實(shí)施關(guān)聯(lián)存儲(chǔ)碎片收集或者將對(duì)象在新產(chǎn)生對(duì)象存儲(chǔ)區(qū)域中保持更長(zhǎng)的時(shí)間嗎?在哪一個(gè)特定時(shí)刻必須實(shí)施一輪完整的存儲(chǔ)碎片收集,以確保所有存儲(chǔ)器在消耗光之前有時(shí)間來(lái)完成這一過(guò)程?
關(guān)鍵的一點(diǎn)是“協(xié)調(diào)步伐”以確保存儲(chǔ)碎片收集器總是在應(yīng)用程序之前,避免最終可能產(chǎn)生的所有滯后,并且獲得真正的實(shí)時(shí)性和確定型的行為。當(dāng)然,通常這都取決于應(yīng)用行為良好這樣的假定,也就是說(shuō),這些應(yīng)用并不會(huì)非??焖俚胤峙浜歪尫糯鎯?chǔ)空間,從而導(dǎo)致存儲(chǔ)碎片收集器不能協(xié)調(diào)工作。在那種情況下,因?yàn)闆](méi)有足夠的存儲(chǔ)空間可以使用,會(huì)導(dǎo)致存儲(chǔ)碎片收集器需要花時(shí)間來(lái)釋放存儲(chǔ)器。需要多少緩沖器取決于存儲(chǔ)碎片收集器的效率以及最壞情況下應(yīng)用的行為。提高關(guān)聯(lián)存儲(chǔ)碎片收集的效率,就減少了需要獲得實(shí)時(shí)性能所必須的緩沖器總數(shù)。
討論如何達(dá)到這樣的一種奇跡超出了本文的范疇。一個(gè)優(yōu)秀的存儲(chǔ)碎片收集器應(yīng)該能夠體現(xiàn)許多關(guān)于內(nèi)部的信息。
存儲(chǔ)碎片收集器的評(píng)價(jià)
在評(píng)價(jià)系統(tǒng)性能時(shí),存儲(chǔ)器使用以及存儲(chǔ)碎片收集的開(kāi)銷是關(guān)鍵的一個(gè)統(tǒng)計(jì)量。許多存儲(chǔ)碎片收集器都提供一種測(cè)量API來(lái)查詢存儲(chǔ)空間的創(chuàng)建、收集、以及從新產(chǎn)生對(duì)象存儲(chǔ)空間到主要存儲(chǔ)器空間升級(jí)的比率。跟蹤應(yīng)用隨時(shí)間的行為的能力,對(duì)于進(jìn)一步的性能調(diào)整很有價(jià)值。
對(duì)性能進(jìn)一步調(diào)整的工具通常關(guān)注測(cè)量對(duì)象創(chuàng)建和撤銷的比率。高明的程序員通常都知道如何通過(guò)重寫代碼打亂對(duì)象次序來(lái)極大地提高速度。我們有一個(gè)Java程序需要將幾千個(gè)時(shí)間信息(長(zhǎng)總數(shù))轉(zhuǎn)換為字符串。有一種標(biāo)準(zhǔn)的Java類型方法可以一步實(shí)現(xiàn)這種轉(zhuǎn)換,但是在它內(nèi)部創(chuàng)建(并且丟棄)了一個(gè)“日期格式化程序”對(duì)象。將根據(jù)步長(zhǎng)重新替換高級(jí)運(yùn)算,就能夠得到一種準(zhǔn)確的日期格式化程序?qū)ο?。這樣就節(jié)省了用于創(chuàng)建(以及存儲(chǔ)碎片收集)幾千個(gè)日期格式化程序?qū)ο笏枰臅r(shí)間。
有時(shí)候應(yīng)用程序知道什么時(shí)候會(huì)被閑置,這是通知存儲(chǔ)碎片收集器啟動(dòng)一個(gè)完整的存儲(chǔ)碎片收集的最好時(shí)機(jī)。要做到這一點(diǎn)就需要利用一個(gè)控制API來(lái)影響存儲(chǔ)碎片收集器的行為。然
而,從前面的討論中可以了解到,存儲(chǔ)碎片收集器通常都比較清楚什么時(shí)候應(yīng)該清理這些存儲(chǔ)碎片。
本文小結(jié)
一般來(lái)說(shuō),存儲(chǔ)碎片收集以及特殊情況下的關(guān)聯(lián)存儲(chǔ)碎片收集已經(jīng)成為近年來(lái)人們不斷研究的課題。關(guān)聯(lián)存儲(chǔ)碎片收集最先出現(xiàn)在桌面應(yīng)用環(huán)境中。比如Sun的HotSpot JVM就是采用關(guān)聯(lián)存儲(chǔ)碎片收集。增量式存儲(chǔ)碎片收集由于減少了等待時(shí)間,所以通常在嵌入式領(lǐng)域應(yīng)用更多。HotSpot也可以進(jìn)行增量式存儲(chǔ)碎片收集,但是時(shí)間增量非常大,在桌面應(yīng)用中存儲(chǔ)碎片收集的進(jìn)展被認(rèn)為比等待時(shí)間更重要。
關(guān)聯(lián)存儲(chǔ)碎片收集在性能上提升了一個(gè)數(shù)量級(jí)。它極大地提高了增量式存儲(chǔ)碎片收集的效率。嵌入式應(yīng)用開(kāi)發(fā)人員會(huì)發(fā)現(xiàn),綜合運(yùn)用增量式存儲(chǔ)碎片收集以及關(guān)聯(lián)存儲(chǔ)碎片收集會(huì)得到最好的存儲(chǔ)碎片收集效果,也可以調(diào)整等待時(shí)間以適合響應(yīng)時(shí)間的要求。