青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

coreBugZJ

此 blog 已棄。

Java 理論與實踐: 垃圾收集簡史 (轉)

垃圾收集的好處是無可爭辯的 ―― 可靠性提高、使內存管理與類接口設計分離,并使開發者減少了跟蹤內存管理錯誤的時間。著名的懸空指針和內存泄漏問題在 Java 程序中再也不會發生了(Java 程序可能會出現某種形式的內存泄漏,更精確地說是非故意的對象保留,但是這是一個不同的問題)。不過,垃圾收集不是沒有代價的 ―― 其中包括對性能的影響、暫停、配置復雜性和不確定的結束 (nondeterministic finalization)。


一個理想的垃圾收集實現應該是完全不可見的 ―― 沒有垃圾收集暫停、沒有因為垃圾收集而產生的 CPU 時間損失、垃圾收集器不會與虛擬內存或者緩存有負面的互動,并且堆不需要大于應用程序的 駐留空間(即堆占用)。當然,沒有十全十美的垃圾收集器,但是垃圾收集器在過去十年中已經有了很大改進。


選項與選擇


1.3 JDK 包括三種不同的垃圾收集策略,1.4.1 JDK 包括六種垃圾收集策略以及 12 種以上用于配置和優化垃圾收集的命令行選項。它們有什么不同?為什么需要有這么多選項?


不同的垃圾收集實現使用不同的策略來識別和收回不可到達的對象,它們與用戶程序和調度器以不同的方式互動。不同類型的應用程序對于垃圾收集有不同的要求 ―― 實時應用程序會將要求收集暫停的持續時間短并且有限制,而企業應用程序可能允許更長時間和可預測性更低的暫停以獲得更高的吞吐能力。



垃圾收集如何工作?


有幾種垃圾收集的基本策略:引用計數、標記-清除、標記-整理 (mark-compact) 和復制。此外,一些算法可以以 增量 方式完成它們的工作(不需要一次收集整個堆,使得收集暫停時間更短),一些算法可以在用戶程序運行時運行( 并發收集)。其他算法則必須在用戶程序暫停時一次進行整個收集(即所謂的 stop-the-world收集器)。最后,還有混合型的收集器,如 1.2 和以后版本的 JDK 使用的分代收集器,它對堆的不同區域使用不同的收集算法。

在對垃圾收集算法進行評價時,我們可能要考慮以下所有標準:

  • 暫停時間。收集器是否停止所有工作來進行垃圾收集?要停止多長時間?暫停是否有時間限制?
  • 暫停的可預測性。垃圾收集暫停是否規劃為在用戶程序方便而不是垃圾收集器方便的時間發生?
  • CPU 占用。總的可用 CPU 時間用在垃圾收集上的百分比是多少?
  • 內存大小。許多垃圾收集算法需要將堆分割成獨立的內存空間,其中一些空間在某些時刻對用戶程序是不可訪問的。這意味著堆的實際大小可能比用戶程序的最大堆駐留空間要大幾倍。
  • 虛擬內存交互。在具有有限物理內存的系統上,一個完整的垃圾收集在垃圾收集過程中可能會錯誤地將非常駐頁面放到內存中來進行檢查。因為頁面錯誤的成本很高,所以垃圾收集器正確管理引用的區域性 (locality) 是很必要的。
  • 緩存交互。即使在整個堆可以放到主內存中的系統上 ―― 實際上幾乎所有 Java 應用程序都可以做到這一點,垃圾收集也常常會有將用戶程序使用的數據沖出緩存的效果,從而影響用戶程序的性能。
  • 對程序區域性的影響。雖然一些人認為垃圾收集器的工作只是收回不可到達的內存,但是其他人認為垃圾收集器還應該盡量改進用戶程序的引用區域性。整理收集器和復制收集器在收集過程中重新安排對象,這有可能改進區域性。
  • 編譯器和運行時影響。一些垃圾收集算法要求編譯器或者運行時環境的重要配合,如當進行指針分配時更新引用計數。這增加了編譯器的工作,因為它必須生成這些簿記指令,同時增加了運行時環境的開銷,因為它必須執行這些額外的指令。這些要求對性能有什么影響呢?它是否會干擾編譯時優化呢?

不管選擇什么算法,硬件和軟件的發展使垃圾收集更具有實用性。20 世紀 70 和 80 年代的經驗研究表明,對于大型 Lisp 程序,垃圾收集消耗 25% 到 40% 的運行時。垃圾收集還不能做到完全不可見,這肯定還有很長的路要走。


基本算法

所有垃圾收集算法所面臨的問題是相同的 ―― 找出由分配器分配的,但是用戶程序不可到達的內存塊。不可到達是什么意思?可以以兩種方式之一訪問內存塊 ―― 或者用戶程序在 根 (root)中有對這一內存塊的引用,或者在另一個可到達的塊中有對這個塊的引用。在 Java 程序中,根是對靜態變量中或者活躍的堆棧框架上的本地變量中所包含的對象的引用。可到達的對象集是指向關系下根集的傳遞閉包。


引用計數

最直觀的垃圾收集策略是引用計數。引用計數很簡單,但是需要編譯器的重要配合,并且增加了賦值 函數 (mutator)的開銷(這個術語是針對用戶程序的,是從垃圾收集器的角度來看的)。每一個對象都有一個關聯的引用計數 ―― 對該對象的活躍引用的數量。如果對象的引用計數是零,那么它就是垃圾(用戶程序不可到達它),并可以回收。每次修改指針引用時(比如通過賦值語句),或者當引用超出范圍時,編譯器必須生成代碼以更新引用的對象的引用計數。如果對象的引用計數變為零,那么運行時就可以立即收回這個塊(并且減少被回收的塊所引用的所有塊的引用計數),或者將它放到遲延收集隊列中。


許多 ANSI C++ 庫類,比如 string ,使用了引用計數來提供垃圾收集的特性。通過重載賦值操作符并利用 C++ 作用域提供的確定性結束,C++ 程序可以將 string 類當成是被收集的垃圾那樣使用。引用計數很簡單,很適用于增量收集,收集過程一般會得到好的引用區域性,但是出于幾個理由,它很少在生產垃圾收集器中使用,如它不能回收不可到達的循環結構(彼此直接或者間接引用的幾個對象,如循環鏈接的列表或者包含指向父節點的反向指針的樹)。


跟蹤收集器

JDK 中的標準垃圾收集器都沒有使用引用計數,相反,它們都使用某種形式的 跟蹤收集器 (tracing collector)。跟蹤收集器停止所有工作(盡管不需要在收集的整個過程中都這樣)并開始跟蹤對象,從根集開始沿著引用跟蹤,直到檢查了所有可到達的對象。可以在程序注冊表中、每一個線程堆棧中的(基于堆棧的)局部變量中以及靜態變量中找到根。


標記-清除收集器

最早由 Lisp 的發明人 John McCarthy 于 1960 年提出的最基本的跟蹤收集器形式是 標記―清除收集器,它停止所有工作,收集器從根開始訪問每一個活躍的節點,標記它所訪問的每一個節點。走過所有引用后,收集就完成了,然后就對堆進行清除(即對堆中的每一個對象進行檢查),所有沒有標記的對象都作為垃圾回收并返回空閑列表。圖 1 展示了垃圾收集之前的堆,陰影塊是垃圾,因為用戶程序不能到達它們:


圖 1. 可到達和不可到達的對象
可到達和不可到達的對象

標記-清除實現起來很簡單,可以容易地回收循環的結構,并且不像引用計數那樣增加編譯器或者賦值函數的負擔。但是它也有不足 ―― 收集暫停可能會很長,在清除階段整個堆都是可訪問的,這對于可能有頁面交換的堆的虛擬內存系統有非常負面的性能影響。


標記-清除的最大問題是,每一個活躍的(即已分配的)對象,不管是不是可到達的,在清除階段都是可以訪問的。因為很多對象都可能成為垃圾,這意思著收集器花費大量精力去檢查并處理垃圾。標記-清除收集器還容易使堆產生碎片,這會產生區域性問題并可以造成分配失敗,即使看來有足夠的自由內存可用。


復制收集器

在另一種形式的跟蹤收集器 ―― 復制收集器中,堆被分成兩個大小相等的半空間,其中一個包含活躍的數據,另一個未使用。當活躍的空間占滿以后,程序就會停止,活躍的對象被從活躍的空間復制到不活躍的空間中。空間的角色就會轉換,原來不活躍的空間成為了新的活躍空間。


復制收集的優點是只訪問活躍的對象,這意味著不會檢查垃圾對象,也不需要將它們頁交換到內存中或者送到緩存中。復制收集器的收集周期時間是由活躍對象的數量決定的。不過,復制收集器因為要將數據從一個空間復制到另一個空間、調整所有引用以指向新備份而增加了成本。特別是,長壽的對象在每次收集時都要來回復制。


堆整理

復制收集器有另一個好處,活躍對象集會被整理到堆的底部。這不僅改進了用戶程序的引用區域性并消除了堆碎片,而且極大地減少了對象分配的成本 ―― 對象分配變成了在堆頂部的指針上增加指針。不需要維護自由列表或者后備列表,或者使用性能最佳或者第一合適的算法 ―― 分配 N 字節就是在堆頂部指針上加 N 并返回前一個值這么簡單,如清單 1 所示:


清單 1. 復制收集器中廉價的內存分配
void *malloc(int n) { 
    if (heapTop - heapStart < n)
        doGarbageCollection();
    void *wasStart = heapStart;
    heapStart += n;
    return wasStart;
}

為非垃圾收集語言實現了復雜內存管理方案的開發人員可能會對復制收集器中廉價的內存分配感到吃驚 ―― 就是指針加法這么簡單。以前的 JVM 實現沒有使用復制收集器 ―― 這可能是對象分配是昂貴的這一想法是如此普遍的原因之一,開發人員仍然下意識地假設分配成本與其他語言(如 C)類似,而事實上在 Java 運行時中可能要廉價得多。不但是分配成本減少了,而且對于在下次收集之前成為垃圾的對象,解除分配的成本為零,因為既不會訪問也不會復制垃圾對象。


標記-整理收集器

復制算法的性能很優異,但是它有一個缺點是需要兩倍于標記-清除收集器所需要的內存。 標記-整理 算法結合了標記-清除和復制,避免了這個問題,代價是增加了一些收集復雜性。與標記-清除類似,標記-整理是兩階段過程,在標記階段訪問并標記每個活躍對象。然后,復制標記的對象,使所有活躍對象被整理到堆的底部。如果每一次收集時進行徹底的整理,那么得到的堆就類似于復制收集器的結果 ―― 在堆的活躍部分與自由部分有明確的界線,這樣分配成本與復制收集器相當。長壽的對象趨向于沉在堆的底部,這樣就不會像在復制收集器中那樣反復復制它們。


選擇哪一種呢?

那么 JDK 使用了哪種方式進行垃圾收集呢?在某種意義上,使用了所有的方式。早期的 JDK 使用了單線程的標記-清除或者標記-清除-整理收集器。1.2 及以后的 JDK 使用了混合的方式,稱為 分代收集,其中根據對象的年齡將堆分為幾個部分,不同的代是用不同的收集算法收集的。


分代收集證明是非常高效的,盡管在運行時它需要更多的簿記。在下一個月的 Java 理論與實踐 中,除了介紹 1.4.1 JVM 提供的所有其他垃圾收集選項之外,我們還將探討分代收集是如何工作的以及 1.4.1 JVM 是如何使用它的。在下下篇文章中,我們將分析垃圾收集對性能的影響,包括揭示與內存管理有關的性能神話。



參考資料

關于作者

Brian Goetz 在過去 15 年間一直從事專業軟件開發。他是 Quiotix 的首席顧問,該公司是一家位于加利福尼亞州洛斯拉圖斯的軟件開發和咨詢公司,他也參與了幾個 JCP 專家組的工作。請參閱流行的業界出版物中 Brian 已經 發表和即將發表的文章。您可以通過 brian@quiotix.com與 Brian 聯系。

posted on 2012-04-01 18:27 coreBugZJ 閱讀(369) 評論(0)  編輯 收藏 引用 所屬分類: 技術視野ProgrammingLanguageLisp

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲欧美日韩精品久久奇米色影视 | 久久精品视频亚洲| 在线综合欧美| 亚洲制服少妇| 久久国产精品亚洲va麻豆| 久久亚洲影院| 欧美国产日韩精品免费观看| 欧美成人午夜| 亚洲美女免费精品视频在线观看| 亚洲精品社区| 午夜欧美大尺度福利影院在线看| 久久精品日韩欧美| 欧美激情网友自拍| 国产欧美精品xxxx另类| 亚洲第一二三四五区| 一本色道久久综合亚洲精品不卡| 午夜视频精品| 欧美成人免费在线视频| 99国产精品99久久久久久| 亚洲欧美激情视频在线观看一区二区三区| 久久精品视频99| 欧美视频在线观看一区二区| 极品av少妇一区二区| 亚洲一级片在线看| 欧美本精品男人aⅴ天堂| 99在线热播精品免费99热| 久久gogo国模裸体人体| 欧美日韩成人在线播放| 影音先锋日韩精品| 翔田千里一区二区| 亚洲日本精品国产第一区| 亚洲欧美亚洲| 欧美日韩一区在线视频| 91久久精品国产91性色tv| 久久国产毛片| 亚洲一区二区三区在线| 欧美国产日韩精品免费观看| 黄色一区二区在线| 欧美一区二区视频97| 亚洲久久成人| 欧美大片在线看| 亚洲第一综合天堂另类专| 欧美在线观看一区二区| 99视频在线观看一区三区| 免费成人毛片| 伊人夜夜躁av伊人久久| 久久国产一二区| 亚洲图片欧洲图片av| 欧美精品一卡二卡| 一本色道久久综合一区| 免费久久久一本精品久久区| 中文av一区二区| 欧美日韩精品| 亚洲精品中文字幕在线| 欧美+日本+国产+在线a∨观看| 一个色综合av| 91久久久一线二线三线品牌| 美女日韩欧美| 亚洲激情视频网| 欧美成人按摩| 久久先锋资源| 亚洲国产小视频在线观看| 免费成人在线观看视频| 久久久综合网站| 在线电影国产精品| 女同性一区二区三区人了人一| 久久久美女艺术照精彩视频福利播放| 黄色成人在线免费| 欧美国产另类| 欧美国产一区二区| 中文国产一区| 亚洲免费一区二区| 狠狠色噜噜狠狠狠狠色吗综合| 久久人体大胆视频| 久热精品视频在线观看| 亚洲青色在线| 99热这里只有成人精品国产| 国产精品丝袜久久久久久app| 久久精品三级| 欧美成人精品一区| 亚洲永久视频| 久久久久成人网| 99热这里只有精品8| 亚洲一区二区三区乱码aⅴ蜜桃女| 国产欧美一区二区三区久久 | 欧美国产亚洲另类动漫| 欧美顶级艳妇交换群宴| 亚洲一区在线直播| 欧美在线啊v| 亚洲精品综合精品自拍| 亚洲一区二区三区高清| 在线不卡中文字幕| 亚洲六月丁香色婷婷综合久久| 亚洲国产精品一区| 国产精品国产精品国产专区不蜜| 久久国产精品99精品国产| 欧美**人妖| 欧美影视一区| 欧美精品一区二| 久久久久九九九九| 欧美午夜精品理论片a级大开眼界 欧美午夜精品理论片a级按摩 | 亚洲一级在线观看| 久久久国产午夜精品| 亚洲一区久久久| 久久久噜噜噜久久中文字幕色伊伊| 蜜臀va亚洲va欧美va天堂| 依依成人综合视频| 亚洲图片欧美午夜| 亚洲国产一区二区a毛片| 亚洲你懂的在线视频| 亚洲精品美女在线| 欧美在线影院在线视频| 亚洲一区二区三区免费视频| 免播放器亚洲| 久久久久青草大香线综合精品| 欧美日韩成人一区| 欧美激情一区在线观看| 国产综合一区二区| 在线亚洲美日韩| 99精品视频免费在线观看| 久久精品在线免费观看| 久久gogo国模啪啪人体图| 国产精品多人| 亚洲片在线资源| 久久九九热re6这里有精品| 欧美一区二区私人影院日本 | 国产精品爽爽ⅴa在线观看| 亚洲欧洲在线播放| 在线日韩av片| 久久久人成影片一区二区三区| 久久er精品视频| 国产精品视频观看| 亚洲综合电影一区二区三区| 亚洲欧美另类综合偷拍| 国产精品国产a级| 亚洲欧美成人一区二区在线电影| 亚洲一线二线三线久久久| 欧美视频二区36p| 亚洲私人影院在线观看| 午夜精品成人在线| 国产欧美日韩视频在线观看 | 欧美一区午夜精品| 久久精品论坛| 国产一区二区三区电影在线观看 | 亚洲东热激情| 日韩午夜黄色| 欧美性猛交xxxx乱大交蜜桃| 亚洲视屏在线播放| 久久狠狠久久综合桃花| 樱桃视频在线观看一区| 欧美成人精品高清在线播放| 亚洲人成网站色ww在线| 亚洲午夜高清视频| 国产麻豆9l精品三级站| 久久国产精品第一页| 欧美成人亚洲成人| 亚洲少妇诱惑| 国产一区二区三区免费观看| 久久午夜激情| 一本一本久久a久久精品牛牛影视| 久久av老司机精品网站导航| 亚洲成色精品| 国产精品国产亚洲精品看不卡15| 亚洲一区二区在线免费观看| 国产精品高潮呻吟视频| 国产精品视频精品| 欧美大色视频| 日韩写真在线| 久久久精品tv| 亚洲三级观看| 国产精品视频观看| 狼人天天伊人久久| 99精品视频一区| 久久午夜国产精品| 在线一区亚洲| 亚洲成色最大综合在线| 国产精品老牛| 欧美电影在线观看| 欧美一站二站| 一区二区三区波多野结衣在线观看| 久久精品国产免费看久久精品| 亚洲激情偷拍| 国产日韩欧美不卡在线| 欧美精品一区在线发布| 欧美一区二区三区在| 日韩一级黄色片| 女同一区二区| 久久久久久一区| 亚洲欧美日韩国产中文| 最新国产の精品合集bt伙计| 国产模特精品视频久久久久| 欧美日韩高清在线| 麻豆精品在线播放| 欧美在线免费观看亚洲| 亚洲午夜在线观看视频在线| 亚洲激情女人| 一区二区视频免费完整版观看| 国产精品xxxav免费视频| 欧美激情欧美狂野欧美精品| 久久另类ts人妖一区二区|