成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一文帶你了解經典的 Java 垃圾回收機制

新聞 前端
在 Java 8 中,HotSpot 虛擬機的默認垃圾回收器是 ParallelOld。在 Java 11 中,默認回收器變成了 G1。

 [[326097]]

在 Java 8 中,HotSpot 虛擬機的默認垃圾回收器是 ParallelOld。在 Java 11 中,默認回收器變成了 G1。

注意:從技術上講,回收器的切換是在 Java 9 中進行的,但 G1 的主要增強是在 Java 10 和 11 中完成的。但實際上,很少有公司使用 Java LTS 以外的版本。

在本文中,我們將討論垃圾回收理論的一些基礎知識,以及這些理論在 HotSpot 中是如何實現的。這也將解釋為什么要切換 Java 的默認垃圾回收器,以及 Java 垃圾回收方法在近來發生的一些變化。

1. 基本概念

垃圾回收是系統的一種“清理”活動,獨立于應用程序的主處理線程,試圖找出不再被使用的內存并將其釋放以便可以繼續重用。

Dijkstra 對垃圾回收的定義清晰地指出,引用計數是自動內存管理的一種形式,但不屬于垃圾回收。

引用計數會在程序運行時更新每個對象的元數據(例如,在對一個引用類型對象的某個字段賦值時)。元數據的更新需要在應用程序線程上進行,因此不能清晰地將其劃分為獨立的活動。

回收算法從 root(一組已知是存活對象)開始,通過跟蹤指針來確定存活對象。

這些跟蹤回收器實現了圖算法,將堆內存劃分為存活的和可回收的。

在現代垃圾回收文獻中,并發(Concurrent)和并行(Parallel)都被用來描述回收算法。它們聽起來像是同義詞,但實際上有著完全不同的含義:

  • 并發——回收線程獨立于應用程序線程運行;
  • 并行——使用多個線程來執行垃圾回收算法。

它們可以被看成是另外兩個術語的對立面——并發是 stop-the-world(STW)的對立面,并行是 single-thread(單線程)的對立面。

實際的垃圾回收器分為多個階段,每個階段還可能具備多種特征。

例如,某個階段可能是單線程并發,或者是并行 STW。

注意:并發回收器比 STW 回收器要復雜得多。它們在計算開銷方面要大得多,而且它們的行為還有需要注意的地方。

其他你應該知道的垃圾回收術語:

  • Exact——Exact 回收器擁有足夠的類型信息,能夠區分 int 和指針之間的區別。
  • 驅逐(Evacuate)——移動(驅逐)存活對象到內存的另一個區域。在回收周期結束時,源內存區域變成空的,可以被重用。
  • 壓縮(Compact)——在回收周期結束時,存活的對象被連續地放在內存的前部區域,剩下的區域可被重用。

Exact 是一種保守模式,缺乏精確的信息,因此通常會造成更大的內存浪費。

一些資料還提到了移動回收器——包括壓縮和驅逐算法。但這兩種類型之間的差異太大,把它們組合在一起通常用處不大。

非移動回收器被稱為就地回收器。這些算法需要知道可用內存塊的列表才能夠處理內存碎片以及合并可用的內存塊。

2. HotSpot 中的一些設計考慮

我們從定義開始,先來考慮一些基本的事實:

  • 移動回收器分配的對象在其生命周期期間沒有穩定的內存地址。
  • 壓縮回收器可用避免出現內存碎片。
  • 驅逐回收器也可以避免內存碎片化,并可以實現對存活對象進行部分壓縮。
  • 如果堆只由一個內存池組成,則無法使用驅逐算法回收。

分代假設基于對面向對象系統運行時行為的觀察,它大致將對象分為兩類:短期的臨時對象和用于執行程序任務的長期對象。

注意:分代回收器并不一定總是比非分代回收器更高效,但幾乎所有的應用程序都會從分代回收器中獲得好處。

回收算法的 mark-sweep-compact(根據 Blackburn 和 McKinley)是這樣定義的:

  • 標記(Mark):通過跟蹤對象圖來識別存活的對象。
  • 清掃(Sweep):讓存活對象留在原地,同時識別出可釋放的空間。
  • 驅逐(Evacuate):將存活對象轉移到另一個內存池,以此來釋放空間。
  • 壓縮(Compact):通過移動同一內存池中的存活對象來釋放空間。

在分代回收算法中,年輕代回收器和老年代回收器通常使用的是完全不同的算法。

這導致我們很難準確地對不同階段采用不同算法的回收器進行歸類。例如,在 CMS 中,年輕代是通過驅逐算法那進行回收的,而老年代是通過標記清除算法進行回收的,如果并發回收失敗(例如由于碎片),則退回到標記壓縮算法。

3. HotSpot 中的年輕代垃圾回收

在 HotSpot 中,傳統的回收器將內存劃分為 4 個內存池,分別是 Eden、Survivor 0、Survivor 1 和 Tenured。前三個被統稱為年輕代,Tenured 是老年代。

年輕代空間是在年輕代回收周期中進行回收的,使用了并行 STW 驅逐算法, 將存活的對象轉移到一個空間。

回收算法在當前活動的內存池中標記存活的對象,然后將其撤到非活動的內存池中。在回收結束時,兩個空間被顛倒過來——活動的內存池變為非活動的(即為空),而非活動的變為活動的。有時候這也被叫作“半球”(hemispehric)回收。

半球回收可能會浪費內存。單遍算法無法預先知道正在回收的內存區域中有多少對象是存活的。這意味著用于存放驅逐對象的區域必須和被清理的區域一樣大——因此算法需要兩倍于實際存活對象大小的內存空間。

它還意味著不管在什么時候都有一半的空間是空的。這些特點導致它不適用于現代工作負載的老年代垃圾回收,因為這些老年代的對象集合可能很大:實際上,在生產環境中,HotSpot 回收器不會使用半球回收算法。

半球回收算法被用于回收年輕代。它非常適用于符合分代假設的工作負載——即內存區域里大部分都是垃圾對象。回收器受益于這樣的一個事實:存活對象總是從年輕代被提升到老年代。

驅逐回收器的另一個主要優點是它們處理空閑空間的方式。最簡單的方法是使用指向空閑空間的指針,當存活對象被驅逐時,很“自然”地被壓縮。

驅逐算法是 OpenJDK 年輕代回收器的典型算法,它使用了對象跟蹤。不過,回收只在一個階段中進行,沒有單獨的標記、清除或壓縮階段。

4. 分代假設的后果

對象的生存期通常是未知的,而且在實際應用程序中會動態發生變化。因此,追蹤對象的實際生存周期是不可行的。

相反,HotSpot 記錄了對象在垃圾回收過程中存活下來的次數,只需要在對象頭部的元數據里添加幾個比特的信息,在對象經歷了足夠多的垃圾回收之后,它就會被移動(提升)到更老的一代,由不同的垃圾回收器來管理。

這種機制與應用程序的內存分配速度存在一種有趣的交互。如果分配速度加快,那么年輕代將更快被填滿——但“短命對象”的預期壽命(以毫秒為單位)保持不變。

這可能會導致更多對象在回收周期中存活下來,從而導致年輕代空間充滿了還沒有資格提升到老年代的對象。在這種情況下,JVM 別無選擇,只能提前提升一些對象——這導致了“過早提升”。

很多這樣的對象實際上都是短命的,在進入老年代后很快就會消失。可惜的是,JVM 沒有回收它們的機制,要等到老年代空間的下一個回收周期才能回收它們。

5. 垃圾回收算法的復雜性

開發人員經常對垃圾回收算法進行復雜性分析(有時候也叫作“大 O”)。然而,在實踐當中,這種做法實際上并不是很令人滿意。

他們可能天真地認為標記和壓縮階段的時間復雜度與活動對象集合的大小成線性關系,而清除階段與整個堆大小成線性關系。

然而,即使不考慮在實際實現當中可能無法清晰地進行階段隔離(如上面討論的 HotSpot 年輕代回收器),仍然存在一個更深層次的問題。

垃圾回收本質上是一種通用算法。這意味著大 O 分析中的固有假設——當數據集增大時,起作用的是限制性行為——是不正確的。

生產環境中的算法需要在面對所有可能的輸入和工作負載表現出可接受的行為。它們的漸近性行為與整體性能是不匹配的。

換句話說,活動對象集合和堆大小本質上是獨立變化的(例如,不同的對象圖拓撲)。這意味著對于不同的工作負載,縮放因子會產生非常不一樣的效果。

例如,壓縮時需要復制字節,因此,盡管壓縮階段在活動對象集合的大小上是呈線性的,但其他因素可能與要移動的對象大小有關。對于包含大量元素的大數組,這種說法就更加站不住腳。

對于各種不同形式的回收算法,還存在一些眾所周知的二級效應。例如,在對只有少量存活對象的內存區域(“稀疏堆”)執行壓縮時,活動的對象將被合并到更密集的區域。如果對象的生命周期很長,那么這個區域對于后續的回收周期來說就不那么稀疏了。

我們可以看到,與 CMS 之類的就地回收器相比,在程序的整個生命周期中,長壽對象將保持稀疏分布。事實上,隨著時間的推移,空閑空間將變得越來越碎片化,空閑內存塊列表的管理將變得越來越昂貴。

總的來說,不同回收方法的時間和空間成本模型是不同的,簡單的算法復雜度分析也不是很管用。在 HotSpot 中,如果沒有足夠的連續空間,就地回收器最終會退回到壓縮回收器。

6. 總結

我們討論了 Java 虛擬機的垃圾回收機制。垃圾回收是計算機科學的一個成熟的領域,HotSpot 的垃圾回收器經過了良好的測試,可以很好地處理大堆工作負載。大多數 Java 應用程序不需要過多地擔心垃圾回收行為。

如果對垃圾回收行為較為敏感,那么深入了解垃圾回收的原則(以及它在 JVM 中是如何實現的)對于開發人員來說會很有幫助。

在最近的 Java 版本中,垃圾回收子系統的改進再次成為關注的熱點。要完全理解這些變化,就要很好地掌握這些基礎知識。后續的文章將詳細討論這些更新,例如,為什么改變了默認回收器、這對升級到 Java 11 的團隊意味著什么。

 

責任編輯:張燕妮 來源: 架構頭條
相關推薦

2021-02-26 05:24:35

Java垃圾回收

2021-10-21 10:01:05

Java選擇排序

2009-06-23 14:15:00

Java垃圾回收

2011-07-04 16:48:56

JAVA垃圾回收機制GC

2023-06-07 16:00:40

JavaScriptV8語言

2023-08-27 21:29:43

JVMFullGC調優

2015-06-04 09:38:39

Java垃圾回收機

2011-06-28 12:39:34

Java垃圾回收

2010-10-13 10:24:38

垃圾回收機制JVMJava

2010-09-25 15:33:19

JVM垃圾回收

2017-03-03 09:26:48

PHP垃圾回收機制

2017-08-17 15:40:08

大數據Python垃圾回收機制

2017-06-12 17:38:32

Python垃圾回收引用

2021-11-05 15:23:20

JVM回收算法

2010-09-16 15:10:24

JVM垃圾回收機制

2010-09-25 15:26:12

JVM垃圾回收

2021-05-27 21:47:12

Python垃圾回收

2021-12-07 08:01:33

Javascript 垃圾回收機制前端

2024-02-22 17:15:22

JS垃圾回收機制

2010-09-26 14:08:41

Java垃圾回收
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一区二区三区视频在线观看 | 日本一级淫片免费啪啪3 | 黑人巨大精品欧美黑白配亚洲 | av国产精品毛片一区二区小说 | 欧美成年视频 | 久久久久久久久久影视 | 天天干天天想 | 国产高清免费在线 | 色婷婷在线视频 | 韩日一区二区三区 | 在线观看免费av片 | 国产精品国产精品国产专区不片 | 亚洲欧美在线视频 | 黄色一级毛片 | 欧区一欧区二欧区三免费 | 国产精品久久国产精品久久 | 国产精品美女一区二区三区 | 国产激情精品 | 国产欧美日韩精品一区 | 亚洲二区在线观看 | 欧美日韩在线观看一区 | 日韩免费视频一区二区 | 蜜臀久久 | 欧美一级黄 | 国产亚洲成av人片在线观看桃 | 一级a性色生活片久久毛片波多野 | 欧美国产日韩一区二区三区 | 色综合天天天天做夜夜夜夜做 | a在线视频 | 中文字幕高清视频 | 日韩一区二区三区精品 | 久久久久久久久久一区 | 亚洲午夜精品一区二区三区他趣 | 伊人网在线播放 | 91精品国产91久久久久久密臀 | 中文字幕人成乱码在线观看 | 亚洲精品女人久久久 | 久久成人一区 | 7777奇米影视 | 国产免费看 | 欧美日韩电影一区 |