JVM——垃圾收集策略

GC的基本問題

什么是GC?

GC 是 garbage collection 的縮寫,意思是垃圾回收——把內存(特別是堆內存)中不再使用的空間釋放掉;清理不再使用的對象。

為什么要GC?

堆內存是各個線程共享的空間,不能無節制的使用。服務器運行的時間通常都很長。累積的對象也會非常多。這些對象如果不做任何清理,任由它們數量不斷累加,內存很快就會耗盡。所以GC就是要把不使用的對象都清理掉,把內存空間空出來,讓項目可以持續運行下去。

如何判斷對象已死?(GC觸發的條件

引用計數算法

簡單來說,引用計數算法就是在對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加一;當引用失效時,計數器值就減一;任何時刻計數器為零的對象就是不可能再被使用的。

但這時會出現一個問題,即當兩個對象相互進行引用時,也就意味著,它永遠都無法”死亡“,就無法進行回收。

Java虛擬機并不是通過引用計數算法來判斷對象是否存活的。

可達性分析算法

通過一系列被稱為 “GC Roots” 的對象作為起始點,從這些節點向下搜索,搜索走過的路徑叫引用鏈。當一個對象到 GC Roots 沒有任何引用鏈相連時,證明此對象不可用,可被判定為 “死亡” 。

在 Java 語言中,可作為 GC Roots 的對象包括:

  1. 在虛擬機棧(棧幀中的本地變量表)中引用的對象,譬如各個線程被調用的方法堆棧中使用到的 參數、局部變量、臨時變量等。

  2. 在方法區中類靜態屬性引用的對象,譬如Java類的引用類型靜態變量。

  3. 在方法區中常量引用的對象,譬如字符串常量池(String Table)里的引用。

  4. 在本地方法棧中JNI(即通常所說的Native方法)引用的對象。

  5. Java虛擬機內部的引用,如基本數據類型對應的Class對象,一些常駐的異常對象(比如 NullPointExcepiton、OutOfMemoryError)等,還有系統類加載器。

  6. 所有被同步鎖(synchronized關鍵字)持有的對象。

  7. 反映Java虛擬機內部情況的JMXBean、JVMTI中注冊的回調、本地代碼緩存等。

再談引用

引用大至分為四種:

  • 強引用:new出來的對象 內存溢出也不會進行回收
  • 軟引用:只被軟引用關聯著的對象,在系統將要發生內存溢出異常前,會把這些對象列進回收范圍之中進行第二次回收,如果這次回收還沒有足夠的內存, 才會拋出內存溢出異常。
  • 弱引用:只要有垃圾收集就會回收
  • 虛引用:回收時收到系統通知

生存還是死亡?(是否真正進行回收)

即使在可達性分析算法中判定為不可達的對象,也不是“非死不可”的,這時候它們暫時還處于“緩 刑”階段,要真正宣告一個對象死亡,至少要經歷兩次標記過程:

  • 第一次標記:是否有與GC Roots相連接的引用鏈
  • 第二次篩選:此對象是否有必要執行finalize()方法(判斷對象能否通過finalize()方法實現自我拯救(避免被回收 )

?finalize()是java.lang.Object類的方法,所有對象默認繼承這個方法。方法體內是空的,說明如果子類不重寫這個方法,那么不執行任何邏輯。

回收方法區(永久代)

永久代的垃圾收集主要回收兩部分內容:廢棄常量和無用的類。

廢棄常量回收比較簡單,就是看是否仍有其他地方引用了此字面量,若無引用,則被回收。而判斷一個類是否需要被回收條件比較苛刻,需要同時滿足下面三個條件才能算是“無用的類”:

  1. 該類所有的實例都已經被回收,也就是java堆中不存在該類的任何實例
  2. 加載該類的ClassLoader已經被回收
  3. 該類對應的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法

分代收集理論

弱分代假說(新生代)

絕大多數對象都是朝生夕滅的。

強分代假說(老年代)

熬過越多次垃圾收集過程的對象就越難以消亡。

垃圾收集器的設計原則

將Java堆根據年齡(年齡即對象熬過垃圾收集過程的次數)劃分出不同的區域進行存儲。當一個對象存活時間越長,年齡越大,我們就將其移動到老年代區域,這樣將新生代和老年代分開管理。每次回收時只關注如何保留少量存活而不是去標記那些大量將要被回收的對 象,就能以較低代價回收到大量的空間;

?跨代引用假說

跨代引用相對于同代引用來說僅占極少數。

當新生代和老年代互相引用,是應該傾向于同時生存或者同時消亡的。如果某個新生代對象存在跨代引用,由于老年代對象難以 消亡,該引用會使得新生代對象在收集時同樣得以存活,進而在年齡增長之后晉升到老年代中,這時 跨代引用也隨即被消除了。

如何記錄每一個對象是否存在及存在哪些跨代引用?

在新生代上建立一個全局的數據結構(記憶集),這個結構把老年代劃分成若干小塊,標識出老年代的哪一塊內存會存在跨代引用。跨代引用的小塊內存里的對象才會被加入到GC Roots進行掃描。

垃圾收集算法

標記-清除算法(老年代

首先標記出需要回收的對象,在標記完成后統一回收掉所有的被標記對象。

缺點

  1. 執行效率不穩定:標記和清除兩個過 程的執行效率都隨對象數量增長而降低;
  2. 內存空間的碎片化問題:標記、清除之后會產生大 量不連續的內存碎片,空間碎片太多可能會導致當以后在程序運行過程中需要分配較大對象時無法找 到足夠的連續內存而不得不提前觸發另一次垃圾收集動作。?

標記-復制算法(新生代)

它將可用內存按需要分成兩塊(實際情況不一定2塊,塊的大小比例不一定),每次只使用其中的一塊。當這一塊的內存用完了,就將還存活著的對象復制到另外一塊上面,然后再把已使用過的內存空間一次清理掉。

新生代通常使用復制算法,因為新生代中對象大多 “朝生夕滅”,每次垃圾收集時有大量對象死去,只有少量存活,復制算法能高效地將少量存活對象復制到另一塊空間,實現快速回收。

優點:每次只對其中一塊進行GC,不用考慮內存碎片的問題,并且實現簡單,運行高效。(適用于新生代,效率高)

缺點:內存縮小了一半。復制的目標空間需要依賴其他空間進行分配擔保(將超出的部分直接放入到老年代區域中)。效率隨對象存活率升高而降低:當對象存活率較高時,需要進行較多復制操作,效率將會變低。

Appel式回收

把新生代分為一塊較大的Eden空間和兩塊較小的 Survivor空間(8:1:1),每次分配內存只使用Eden和其中一塊Survivor。

發生垃圾搜集時,將Eden和Survivor中仍 然存活的對象一次性復制到另外一塊Survivor空間上,然后直接清理掉Eden和已用過的那塊Survivor空間。

當Survivor空間不足以容納一次Minor GC之后存活的對象時,就需要依賴其他內存區域(將超出的部分直接放入到老年代區域中)。

標記-整理算法(老年代)

使用“標記-整理”算法:先標記,再把所有存活的對象向一端移動,然后直接清理端邊界意外的內存。

老年代中對象存活率高,沒有額外空間對其進行分配擔保。如果在老年代使用復制算法,由于存活對象多,復制操作會比較頻繁,效率低下且成本較高。

優點:不會像復制算法、效率隨對象存活率升高而變低。不會像標記-清除算法,產生內存碎片(因為清除前,進行了整理,存活對象都集中到空間一側)。

缺點:主要是效率問題:除像標記-清除算法的標記過程外,還多了需要整理的過程,效率更低。?

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

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

相關文章

用Java模擬打字:深入解析 java.awt.Robot 的鍵盤控制藝術

作為開發者,我們有時會遇到需要自動化用戶界面交互的場景,比如自動化測試、腳本編寫、或者制作一些輔助工具。而模擬鍵盤輸入,尤其是“打字”,是這類自動化任務中非常基礎且常見的一環。 在 Java 中,實現這一目標的利…

JavaScript 入門全講解

JavaScript 入門全講解 一、前言:為什么學習 JavaScript?二、JavaScript 簡史與發展三、JavaScript 基礎語法3.1 變量聲明:var、let、const3.2 數據類型3.3 類型判斷3.4 類型轉換 四、運算符與表達式五、流程控制5.1 條件判斷5.2 switch 語句…

python練習:求數字的階乘

求數字的階乘 eg:5的階乘 54321 """ 求數字的階乘 eg:5的階乘 5*4*3*2*1 """count 1 for i in range(1,6):count count * iprint(count)運行結果:

傳統農耕展陳如何突破?數字多媒體能否重構文化體驗邊界?

農耕文化是中華民族悠久歷史的重要組成部分,它不僅承載著古代先民與自然和諧相處的智慧,也體現了人們對土地和自然的深厚情感。而今,如何有效地傳承和展示這一傳統文化,成為了一個重要的課題。今日,便讓我們聚焦于農耕…

nginx代理websocket時ws遇到僅支持域名訪問的處理

最終改造點 proxy_set_header Host 這一行 未改之前遇到的問題: nginx 日志顯示 https://aaa.bbbb.cn:7413 被解析成了 IP 地址,這通常是因為 DNS 解析的結果被緩存或某些中間層(如負載均衡器、防火墻等)將域名替換為 IP 地址。…

YUM/DNF管理工具

YUM (Yellow dog Updater, Modified) , RHEL8 中默認使用的軟件批量管理工具由原版本的 yum 換成了速度更快的 dnf ( DNF Dandified YUM ),原有的 yum 命令僅為 dnf 的軟鏈接,當然依舊可以使用。 [root…

易基因:何川團隊開發新m6A測序方法 可溫和條件下高分辨率/低背景噪聲檢測m6A修飾|Nature子刊

大家好,這里是專注表觀組學十余年,領跑多組學科研服務的易基因。 RNA和DNA中的化學修飾在多種生物過程中發揮著關鍵作用,包括轉錄調控、RNA降解、蛋白質翻譯和免疫調節等。這些修飾已被新的測序方法以單堿基分辨率定量地繪制出來&#xff0c…

前后端分離: vue3+SpringBoot+ElementPlus+Axios+MyBatisPuls

前后端分離: vue3SpringBoot 項目介紹搭建Vue前端工程axios請求響應攔截跨域 搭建后端TableId,TableName分頁顯示配置Druid數據源帶條件的分頁查詢后端校驗lambda表達式說明 項目介紹 🌟項目頁面 🌟技術棧: 1.前端技術棧: Vue3AxiosElementPlus 2.后端技…

序列密碼算法ShanLooog512設計原理詳解

序列密碼算法ShanLooog512設計原理詳解 ShanLooog512(閃龍512)為序列密碼算法,內部狀態為512比特,密鑰長度為128或256比特,輪函數為FFFFFFFF,循環輪數為24輪,輸出密鑰流為512比特的狀態。與Salsa20類似,內…

Matplotlib可視化基礎

1. 折線圖 matplotlib.pyplot.plot() # 主要參數: x,y -- 接收array,表示X軸和Y軸對應的數據,無默認 color -- 接收特定string,指定線條的顏色,默認為None linestyle -- 接收特定string,指定線條的類型…

阿里云直接對系統云盤擴容

阿里云直接對系統云盤擴容 登錄阿里云控制臺,進入ECS實例管理頁面,檢查目標磁盤的容量是否已更新為擴容后的數值。通過SSH遠程連接服務器,使用命令 lsblk 或 fdisk -l 查看當前磁盤分區和容量,確認擴容后的物理磁盤已被系統識別。…

OpenResty深度解析:從卓伊凡的”隱形主流”論看其深度原理與應用生態-卓伊凡

OpenResty深度解析:從卓伊凡的”隱形主流”論看其深度原理與應用生態-卓伊凡 一、OpenResty技術概述:悄然成為基礎設施的”隱形冠軍” 1.1 OpenResty的”附帶安裝”現象 正如技術觀察者卓伊凡在其《現代Web基礎設施的隱形架構》一文中首次提出的觀點:”OpenResty正在以一…

健康養生:開啟品質生活的密鑰

健康是人生最寶貴的財富,養生則是守護這份財富的關鍵。科學合理的養生方式,能讓我們以更飽滿的狀態擁抱生活。 合理飲食是健康養生的基石。遵循 “食物多樣、谷類為主” 的原則,保證每日攝入足夠的蛋白質、碳水化合物、脂肪、維生素和礦物質。…

湖北理元理律師事務所:債務優化的法律機制與民生實踐

在債務糾紛日益增多的社會背景下,合法、規范的債務管理服務成為民生需求的重要環節。湖北理元理律師事務所作為經國家司法局注冊登記的債事服務機構,以法律為工具,探索出一套覆蓋債務咨詢、規劃與風險防控的服務體系。 1.法律服務的專業化框…

AI日報 - 2025年04月29日

🌟 今日概覽(60秒速覽) ▎🤖 AGI突破 | 巨頭CEO預測AGI時間線,5年內或達人類認知水平;Yann LeCun強調多模態訓練重要性。 關于AGI定義和實現時間的討論升溫,對超越純文本訓練的需求成為共識。 ▎💼 商業動向…

【C++】類和對象(4)

目錄 1. 類型轉換 非explicit的單參數構造函數 示例 explicit的單參數構造函數 示例 不同版本的行為 示例 (單參數) 示例(多參數且其余參數有默認值 ) 示例(多參數且無默認值) 2. static成員變量…

蒼穹外賣10

WebSocket WebSocket是基于TCP的一種新的網絡協議。它實現了瀏覽器與服務器全雙工通信----瀏覽器和服務器只需要完成一次握手,兩者之間就可以創建持久性的連接,并進行雙向數據傳輸。 HTTP協議和WebSocket協議對比: HTTP是短鏈接 WebSocke…

STM32的Flash映射雙重機制

在STM32微控制器中,存在一個重要的內存映射特性:Flash存儲器可以同時出現在兩個不同的地址區域,而且可以通過重映射功能改變CPU啟動時從哪個地址獲取初始指令。 STM32的Flash映射雙重機制 當描述"通常起始于地址0x00000000&#xff0c…

在 Spring Boot 中實現異常處理的全面指南

在現代 Web 應用開發中,異常處理是確保系統健壯性和用戶體驗的關鍵環節。Spring Boot 作為一個功能強大的 Java 框架,提供了靈活的異常處理機制,能夠統一管理應用程序中的錯誤,提升代碼可維護性和響應一致性。2025 年,…

學習記錄:DAY19

Docker 部署與項目需求分析 前言 人總是本能地恐懼未知,令生活陷入到經驗主義的循環之中。但我們終將面對。今天的目標是把 Docker 部署學完,然后對項目進行需求分析。 日程 下午 4:30:Docker 部署項目部分學完了,做下筆記。晚…