程序員的視角:java GC



GC(Garbage Collection 垃圾回收)的概念隨著 java 的流行而被人們所熟知。 實際 GC 最早起源于20世紀60年代的 LISP 語言,是一種自動的內存管理機制。 GC 要解決的問題有 3 個:

1. 回收什么?(what)

2. 何時回收?(when)

3. 如何回收?(how)

回收什么?

清理的是垃圾,回收的是內存空間。

既然 GC 是 java 的自動內存管理機制,那么先看下 java 虛擬機將所管理的內存劃分為不同的區域,如圖1。

如圖1所示,java 虛擬機管理的內存區域分為如下幾個部分:

1. 堆(Heap)

2. 方法區(Method Area)

3. 虛擬機棧(VM Stack)

4. 本地方法棧(Native Method Stack)

5. 程序計數器(Program Counter Register)

其中堆和方法區屬于所有線程共享,而其他區域屬于線程隔離的區域。

下面我們以 java HotSpot 虛擬機為例分別說說每個區域的作用和構成:

堆(Heap)

堆用于存儲對象實例,從內存回收的角度看,由于收集器基本都采用了分代收集算法,所以堆可以進一步細分為:

- Eden 區

- Survivor 0 區 (From)

- Survivor 1 區 (To)

- Old/Tenured 區

其中 Eden、S0、S1 組成了新生代(Young/New Generation),Old/Tenured 為老年代。

方法區(Method Area)

方法區存儲虛擬機加載的類信息、常量、編譯代碼等數據。 HotSpot 虛擬機使用永久代(Permanent Generation)來實現方法區。

虛擬機棧(VM Stack)

虛擬機棧描述的是 java 方法執行的內存模型,每個方法在執行時創建一個棧幀(Stack Frame)。 棧幀中存儲內容主要包含:

- 局部變量表

- 操作數棧

- 動態鏈接

- 方法返回地址

每個方法的執行過程就對應著一個棧幀在虛擬機棧中入棧到出棧的過程。

本地方法棧(Native Method Stack)

本地方法棧與虛擬機棧類似,只不過服務于虛擬機執行 Native 方法時。 HotSpot 虛擬機的實現把虛擬機棧和本地方法棧合二為一。

程序計數器(Program Counter Register)

可以看作是線程執行的字節碼的行號指示器,在虛擬機的概念模型中便于實現分支、循環、跳轉、異常處理和線程切換恢復等基礎功能。 每個線程都有一個獨立的程序計數器。

GC 管理的內存區域主要是堆(Heap),而堆中存放的是對象實例,因此 GC 回收的就是“死亡”(不可能再被使用)的對象占用的內存空間。

何時回收?

既然說到“死亡”的對象,那不得不說下對象的生命周期。

虛擬機通過 new 指令創建了對象,大多數對象創建時在 Eden 區分配內存空間,而一些大對象若 Eden 區不能滿足其空間需求時會直接在 Old/Tenured 區分配。

對象的死亡判定,主流的 GC 實現都是通過可達性分析,形象點來說就是在基于引用建立的對象圖中形成了孤島的對象就是死亡的(可回收的)。

GC 分類

- Minor GC

- Major GC

- Full GC

Minor GC 是針對新生代的回收,當 Eden 區空間滿了時將觸發 Minor GC。

Major GC 是針對老年代的回收,當 Minor GC 發生時會拷貝對象到老年代,這個過程稱為對象晉升(promotion)或老年化(tenuring)。

為了避免對象晉升時老年代空間不足,收集器總是嘗試預測剩余的空間是否足夠以避免對象晉升失敗,當晉升失敗時就會發生 Full GC。

Full GC 是針對整個堆的操作,是非常昂貴的操作。除了在對象晉升失敗時發生 Full GC,當堆自動調整大小時(Heap-Resizing)也會發生,不過可以通過設置 -Xms和-Xmx為相同的值來避免 Heap-Resizing。


如何回收?

Minor GC 將新生代中存活的對象拷貝到 Survivor 區和 Tenured 區。

Major GC 針對老年代區域進行死亡對象標記、清除和內存整理。

Full GC 則包括了所有存活對象的晉升以及老年代的內存回收及整理。

前面泛泛而談了3種垃圾收集方式的過程,而具體則是由垃圾收集器來實現。

截至 JDK 1.7 HotSpot 虛擬機提供的垃圾收集器如圖2所示,一共有 7 種不同作用的收集器。

圖中連線表明它們可以搭配使用。

Serial Collector

如其名,串行的單線程收集器,是目前虛擬機運行在 client 模式下的默認新生代收集器。

ParNew Collector

相當于 Serial 的多線程版本。

Parallel Scavenge Collector

與 ParNew 很像,但它的關注點在達到一個可控制的吞吐量(Throughput),這里吞吐量的定義是 CPU 用于運行用戶代碼的時間與 CPU總消耗時間的比值。

因此 Parallel Scavenge 收集器也經常稱為吞吐優先收集器,它還有個特點是自適應調節策略。 虛擬機會根據當前系統的運行情況收集監控信息,動態調整 Eden與Survivor區比例、晉升老年代對象年齡等參數,以提供最合適的停頓時間或最大的吞吐量。

Serial Old Collector

相當于 Serial 收集器的老年代版本。

Parallel Old Collector

相當于 Parallel Scavenge 收集器的老年代版本。

Concurrent Mark Sweep (CMS) Collector

前述的收集器在執行時都會停止所有的用戶線程執行(Stop-The-World)

CMS 收集器的關注點則是盡可能地縮短垃圾收集時用戶線程的停頓時間,讓垃圾收集和用戶線程并行執行,從而減少應用停頓時間,提升用戶體驗。

當然在獲得低停頓的好處時是付出了吞吐量的代價,通常與 Parallel 系收集器相比吞吐率下降 10%-40%。


CMS 收集器的處理整個過程有如下步驟:

1. 初始標記:找到 GC Roots。

2. 并發標記:標記所有從 GC Roots 可達的對象。

3. 并發預清理:檢查對象引用更新和在并發標記階段晉升到老年代的對象并進行標記。

4. 重新標記:標記預清理階段更新的對象引用。

5. 并發清理:回收死亡對象的內存。

6. 并發重置:重置數據結構為下次運行作準備。

其執行示意如圖3所示

其中步驟1(初始標記)和步驟4( 重新標記)仍然需要 Stop The World,只是相對來說時間較短。

低停頓是 CMS 收集器是的優點,但它也并不完美,它有 3 個明顯缺點:

1. 由于和用戶線程并發執行,所以存在 CPU 爭搶的問題。

2. 無法回收浮動垃圾。

3. CMS 僅進行了標記、清除而未進行整理,容易產生大量內存空間碎片。

CMS 默認啟動的回收線程是 (CPU數量 + 3) / 4,也就是 CPU 在 4 個以上時并發回收線程使用的 CPU 資源不少于 25%。 在并發清理時新產生的垃圾稱為浮動垃圾(Floating Garbage),本次無法收集,當浮動垃圾過多導致預留的內存無法滿足程序需要時觸發, 就可能出現 Concurrent Mode Failure 導致啟用 Serial Old 收集器作為后備進行 Full GC。

Garbage First (G1) Collector

一種新的收集器,在 jdk7u4 開始正式支持,它有如下特點:

1. 多分區的堆組織方式

G1 也是分代收集器,但其組織堆的方式與其他收集器完全不同。它根據不同的用途將堆分為大量(~2000)固定大小的區域(region)。 相同用途的堆也并不連續,G1 依然保留了新生代和老年代的概念,但新生代和老年代不再是物理上隔離的了,它們都是一部分 region 的集合,如圖4所示。

如果一個對象大小超過了普通區域大小的50%,那么它會被分配到一個大區域(humongous)里面。

2. 優先的收集方式

G1 的收集方式追求低停頓,并且建立可預測的停頓時間模型(在 M 毫秒的時間片段內,GC 的時間不得超過 N 毫秒,N < M)。 G1 通過有計劃的避免在整個堆中進行全區域掃描進行垃圾收集,它通過跟蹤各個 region 中垃圾的價值大小(回收獲得的空間及回收所花費的時間的經驗值), 在后臺維護一個優先級列表,每次根據允許的收集時間,優先回收價值最大的 region,這也正式 Garbage-First 名稱的由來。 而對 region 的收集采用的是 Stop-The-World 的方式,增量的將存活的對象復制到一個空 region 里面,這種方式不會產生內存碎片問題。

最后我們引用《Java Garbage Collection Distilled》 一文中的關于 GC 的折衷權衡點來總結下。

俗話說:“從來沒有不勞而獲,當我們得到某些事物的時候,通常不得不放棄另外一些事物”。

當談論垃圾收集的時候,我們主要考慮三個收集器的指標:

1. 吞吐量:花費在 GC 上的時間占整個應用程序工作的比例。

2. 延遲:因為垃圾回收,而引起的響應暫停的時間。

3. 內存:我系統使用內存來存儲狀態,在管理的時候它們常常需要復制和移動。

上述三個指標,吞吐量越大越好,延遲越低越好,內存復制和移動產生的碎片越少越好。 但可惜這三個目標很難同時滿足,很多時候我們都是根據應用類型在其中做出權衡取舍。


轉載于:https://juejin.im/post/5c3483b4518825233b4e66ce

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/252598.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/252598.shtml
英文地址,請注明出處:http://en.pswp.cn/news/252598.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

spring mvc攔截器HandlerInterceptor

本文主要介紹springmvc中的攔截器&#xff0c;包括攔截器定義和的配置&#xff0c;然后演示了一個鏈式攔截的測試示例&#xff0c;最后通過一個登錄認證的例子展示了攔截器的應用 攔截定義 定義攔截器&#xff0c;實現HandlerInterceptor接口。接口中提供三個方法。 public cla…

mysql show 語句大全

mysql show 語句大全 show open tables; 基于本人對MySQL的使用&#xff0c;現將常用的MySQL show 語句列舉如下&#xff1a; 1.show databases ; // 顯示mysql中所有數據庫的名稱 2.show tables [from database_name]; // 顯示當前數據庫中所有表的名稱 3.show columns from …

阿里云Aliplayer高級功能介紹(一):視頻截圖

基本介紹H5 Video是不提供截圖的API的&#xff0c; 視頻截圖需要借助Canvas&#xff0c;通過Canvas提供的drawImage方法&#xff0c;把Video的當前畫面渲染到畫布上&#xff0c; 最終通過toDataURL方法可以導出圖片的base64編碼&#xff0c;基本就完成了圖片截圖的功能。 功能實…

POJ 1151 Atlantis 線段樹+掃描線

解題思路: 先將y軸進行離散化。n個矩形的2n個橫邊縱坐標共構成最多2n-1個區間的邊界&#xff0c;對這些區間編號&#xff0c;建立起線段樹。 x軸記錄左邊和右邊&#xff0c;左邊時是矩形面積增加&#xff0c;覆蓋層數增加邊&#xff0c;右邊是形面積減少&#xff0c;覆蓋層數減…

分頁

1.首先在數據庫中建立一個視圖&#xff08;在aspx中sql查詢語句是view_student不是student&#xff09;&#xff0c;在視圖里創建create view view_student--創建視圖as row_number 行號 一條數據是一行 分頁功能要根據行數運算select *,row_number() over(order by stuNo desc…

NFS服務端的安裝

執行以下四步操作即可完成在虛擬機上安裝完成NFS的服務端&#xff1a;第一步&#xff1a;在虛擬機上安裝nfs服務&#xff1a; sudo apt install nfs-kernel-server 第二步&#xff1a;修改文件 sudo vi /etc/exports 在文件末尾增加 /home/zzf/hisi-sdk 192.16…

【C++STL/紅黑樹】POJ 3481 DoubleQueue

POJ 3481 Double Queue 描述&#xff1a; 新成立的BIG-Bank在不切雷斯特開了一間新辦公室,使用了由IBM羅馬尼亞的現代計算機辦公環境,運用了現代信息技術.一般來說,銀行的每個顧客都有一個識別碼K,并且每一個來銀行的顧客都會被給予一個優先級P.銀行主管的一個大膽想法震驚了公…

基礎表單筆記

表單數據要向服務端提交的話 每個表單都要指定一些屬性就是name""和value"" value就是用戶寫什么就是什么 來提交name就是對這個表單進行一個標識 <from> 輸入用戶名<input type"text" name"user" value""/>這…

PCIE總線-PCI、PCIE關系及信號定義

PCI(Peripheral Component Interconnect)總線規范在上世紀九十年代由Intel提出。在處理器體系結構中&#xff0c;PCI總線屬于局部總線(Local Bus)。局部總線作為系統總線的延伸&#xff0c;主要功能是為了連接外部設備。 處理器主頻的不斷提升&#xff0c;要求速度更快&#x…

SQL Server:SQL Like 通配符特殊用法:Escape

%&#xff1a;匹配零個及多個任意字符&#xff1b; _&#xff1a;與任意單字符匹配&#xff1b; []&#xff1a;匹配一個范圍&#xff1b; [^]&#xff1a;排除一個范圍 &#xff1b;-&#xff1a;連字符 Symbol Meaning like 5[%] 5% like [_]n _n like [a-cdf] a, b, c, d, o…

案例篇-HBase RowKey 設計指南

1.為什么 Rowkey 這么重要 1.1 RowKey 到底是什么 我們常說看一張 HBase 表設計的好不好&#xff0c;就看它的 RowKey 設計的好不好。可見 RowKey 在 HBase 中的地位。那么 RowKey 到底是什么?RowKey 的特點 如下: 類似于 MySQL、Oracle 中的主鍵&#xff0c;用于標示唯一的行…

PCIe簡介及引腳定義

隨著現代處理器技術的發展&#xff0c;在互連領域中&#xff0c;使用高速差分總線替代并行總線是大勢所趨。與單端并行信號相比&#xff0c;高速差分信號可以使用更高的時鐘頻率&#xff0c;從而使用更少的信號線&#xff0c;完成之前需要許多單端并行數據信號才能達到的總線帶…

IDEA下搜狗輸入法輸入中文時卡著不動的參考解決方法

【問題描述】 在IntelliJ IDEA工具的java編輯窗口&#xff0c;給代碼增加注釋時發現&#xff0c;輸入中文時&#xff0c;搜狗輸入法界面不動&#xff0c;只顯示第一個字母。如圖&#xff1a; 我想輸入“根據”兩個字&#xff0c;但搜狗輸入法界面一直卡著不刷新&#xff0c;導…

6U VPX板卡資料:6U VPX 高性能計算存儲板卡

6U VPX板卡資料&#xff1a;6U VPX 高性能計算存儲板卡_hexiaoyan827的博客-CSDN博客_vpx板卡

Android: Custom View和include標簽的區別

Custom View&#xff0c; 使用的時候是這樣的&#xff1a; <com.example.home.alltest.view.MyCustomViewandroid:id"id/customView"android:layout_width"match_parent"android:layout_height"wrap_content"></com.example.home.allte…

七 web爬蟲講解2—urllib庫爬蟲—狀態嗎—異常處理—瀏覽器偽裝技術、設置用戶代理...

如果爬蟲沒有異常處理&#xff0c;那么爬行中一旦出現錯誤&#xff0c;程序將崩潰停止工作&#xff0c;有異常處理即使出現錯誤也能繼續執行下去 1.常見狀態嗎 301&#xff1a;重定向到新的URL&#xff0c;永久性302&#xff1a;重定向到臨時URL&#xff0c;非永久性304&#x…

DVI和HDMI中的TMDS接口協議

TMDS&#xff08;Transition Minimized Differential signal&#xff09;&#xff0c;即過渡調制差分信號&#xff0c;也被稱為最小化傳輸差分信號&#xff0c;是指通過異或及異或非等邏輯算法將原始信號數據轉換成10位&#xff0c;前8為數據由原始信號經運算后獲得&#xff0c…

君子眼中皆好人

從前有個國王&#xff0c;在晚年時思量 著&#xff1a;“我有兩個兒子&#xff0c;我應該把王位傳給哪個兒子來統治這個國家呢&#xff1f;”國王決定考驗一下他的兩位王子&#xff0c;哪位最是忠義仁厚&#xff0c;愛護老百姓的明君。國王叫來長子&#xff0c; 對他說&#xf…

GS使用HTTPS登錄的設置過程

1. Windows 增加角色服務 服務器配置管理器&#xff0c; 添加角色服務 增加角色功能里面有&#xff1a; 證書頒發機構 證書頒發機構 web注冊 2. AD CS配置 主要是next操作 獨立ca 根證書 等 3. inetmgr申請證書 在機器名的一層及上面申請證書 保存證書信息 用來使用CA機構進行簽…