[java八股文][Java虛擬機面試篇]垃圾回收

什么是Java里的垃圾回收?如何觸發垃圾回收?

垃圾回收(Garbage Collection, GC)是自動管理內存的一種機制,它負責自動釋放不再被程序引用的對象所占用的內存,這種機制減少了內存泄漏和內存管理錯誤的可能性。垃圾回收可以通過多種方式觸發,具體如下:

  • 內存不足時:當JVM檢測到堆內存不足,無法為新的對象分配內存時,會自動觸發垃圾回收。
  • 手動請求:雖然垃圾回收是自動的,開發者可以通過調用?System.gc()?或?Runtime.getRuntime().gc()?建議 JVM 進行垃圾回收。不過這只是一個建議,并不能保證立即執行。
  • JVM參數:啟動 Java 應用時可以通過 JVM 參數來調整垃圾回收的行為,比如:-Xmx(最大堆大小)、-Xms(初始堆大小)等。
  • 對象數量或內存使用達到閾值:垃圾收集器內部實現了一些策略,以監控對象的創建和內存使用,達到某個閾值時觸發垃圾回收。

#判斷垃圾的方法有哪些?

在Java中,判斷對象是否為垃圾(即不再被使用,可以被垃圾回收器回收)主要依據兩種主流的垃圾回收算法來實現:引用計數法和可達性分析算法

引用計數法(Reference Counting)

  • 原理:為每個對象分配一個引用計數器,每當有一個地方引用它時,計數器加1;當引用失效時,計數器減1。當計數器為0時,表示對象不再被任何變量引用,可以被回收。
  • 缺點:不能解決循環引用的問題,即兩個對象相互引用,但不再被其他任何對象引用,這時引用計數器不會為0,導致對象無法被回收。

可達性分析算法(Reachability Analysis)

img

Java虛擬機主要采用此算法來判斷對象是否為垃圾。

  • 原理:從一組稱為GC Roots(垃圾收集根)的對象出發,向下追溯它們引用的對象,以及這些對象引用的其他對象,以此類推。如果一個對象到GC Roots沒有任何引用鏈相連(即從GC Roots到這個對象不可達),那么這個對象就被認為是不可達的,可以被回收。GC Roots對象包括:虛擬機棧(棧幀中的本地變量表)中引用的對象、方法區中類靜態屬性引用的對象、本地方法棧中JNI(Java Native Interface)引用的對象、活躍線程的引用等。

#垃圾回收算法是什么,是為了解決了什么問題?

JVM有垃圾回收機制的原因是為了解決內存管理的問題。在傳統的編程語言中,開發人員需要手動分配和釋放內存,這可能導致內存泄漏、內存溢出等問題。而Java作為一種高級語言,旨在提供更簡單、更安全的編程環境,因此引入了垃圾回收機制來自動管理內存。

垃圾回收機制的主要目標是自動檢測和回收不再使用的對象,從而釋放它們所占用的內存空間。這樣可以避免內存泄漏(一些對象被分配了內存卻無法被釋放,導致內存資源的浪費)。同時,垃圾回收機制還可以防止內存溢出(即程序需要的內存超過了可用內存的情況)。

通過垃圾回收機制,JVM可以在程序運行時自動識別和清理不再使用的對象,使得開發人員無需手動管理內存。這樣可以提高開發效率、減少錯誤,并且使程序更加可靠和穩定。

#垃圾回收算法有哪些?

  • 標記-清除算法:標記-清除算法分為“標記”和“清除”兩個階段,首先通過可達性分析,標記出所有需要回收的對象,然后統一回收所有被標記的對象。標記-清除算法有兩個缺陷,一個是效率問題,標記和清除的過程效率都不高,另外一個就是,清除結束后會造成大量的碎片空間。有可能會造成在申請大塊內存的時候因為沒有足夠的連續空間導致再次 GC。
  • 復制算法:為了解決碎片空間的問題,出現了“復制算法”。復制算法的原理是,將內存分成兩塊,每次申請內存時都使用其中的一塊,當內存不夠時,將這一塊內存中所有存活的復制到另一塊上。然后將然后再把已使用的內存整個清理掉。復制算法解決了空間碎片的問題。但是也帶來了新的問題。因為每次在申請內存時,都只能使用一半的內存空間。內存利用率嚴重不足。
  • 標記-整理算法:復制算法在 GC 之后存活對象較少的情況下效率比較高,但如果存活對象比較多時,會執行較多的復制操作,效率就會下降。而老年代的對象在 GC 之后的存活率就比較高,所以就有人提出了“標記-整理算法”。標記-整理算法的“標記”過程與“標記-清除算法”的標記過程一致,但標記之后不會直接清理。而是將所有存活對象都移動到內存的一端。移動結束后直接清理掉剩余部分。
  • 分代回收算法:分代收集是將內存劃分成了新生代和老年代。分配的依據是對象的生存周期,或者說經歷過的 GC 次數。對象創建時,一般在新生代申請內存,當經歷一次 GC 之后如果對還存活,那么對象的年齡 +1。當年齡超過一定值(默認是 15,可以通過參數 -XX:MaxTenuringThreshold 來設定)后,如果對象還存活,那么該對象會進入老年代。

#垃圾回收器有哪些?

img

  • Serial收集器(復制算法): 新生代單線程收集器,標記和清理都是單線程,優點是簡單高效;
  • ParNew收集器 (復制算法): 新生代收并行集器,實際上是Serial收集器的多線程版本,在多核CPU環境下有著比Serial更好的表現;
  • Parallel Scavenge收集器 (復制算法): 新生代并行收集器,追求高吞吐量,高效利用 CPU。吞吐量 = 用戶線程時間/(用戶線程時間+GC線程時間),高吞吐量可以高效率的利用CPU時間,盡快完成程序的運算任務,適合后臺應用等對交互相應要求不高的場景;
  • Serial Old收集器 (標記-整理算法): 老年代單線程收集器,Serial收集器的老年代版本;
  • Parallel Old收集器 (標記-整理算法): 老年代并行收集器,吞吐量優先,Parallel Scavenge收集器的老年代版本;
  • CMS(Concurrent Mark Sweep)收集器(標記-清除算法): 老年代并行收集器,以獲取最短回收停頓時間為目標的收集器,具有高并發、低停頓的特點,追求最短GC回收停頓時間。
  • G1(Garbage First)收集器 (標記-整理算法): Java堆并行收集器,G1收集器是JDK1.7提供的一個新收集器,G1收集器基于“標記-整理”算法實現,也就是說不會產生內存碎片。此外,G1收集器不同于之前的收集器的一個重要特點是:G1回收的范圍是整個Java堆(包括新生代,老年代),而前六種收集器回收的范圍僅限于新生代或老年代

#標記清除算法的缺點是什么?

主要缺點有兩個:

  • 一個是效率問題,標記和清除過程的效率都不高;
  • 另外一個是空間問題,標記清除之后會產生大量不連續的內存碎片,空間碎片太多可能會導致,當程序在以后的運行過程中需要分配較大對象時無法找到足夠的連續內存而不得不提前觸發另一次垃圾收集動作。

#垃圾回收算法哪些階段會stop the world?

標記-復制算法應用在CMS新生代(ParNew是CMS默認的新生代垃圾回收器)和G1垃圾回收器中。標記-復制算法可以分為三個階段:

  • 標記階段,即從GC Roots集合開始,標記活躍對象;
  • 轉移階段,即把活躍對象復制到新的內存地址上;
  • 重定位階段,因為轉移導致對象的地址發生了變化,在重定位階段,所有指向對象舊地址的指針都要調整到對象新的地址上。

下面以G1為例,通過G1中標記-復制算法過程(G1的Young GC和Mixed GC均采用該算法),分析G1停頓耗時的主要瓶頸。G1垃圾回收周期如下圖所示:

img

G1的混合回收過程可以分為標記階段、清理階段和復制階段。

標記階段停頓分析

  • 初始標記階段:初始標記階段是指從GC Roots出發標記全部直接子節點的過程,該階段是STW的。由于GC Roots數量不多,通常該階段耗時非常短。
  • 并發標記階段:并發標記階段是指從GC Roots開始對堆中對象進行可達性分析,找出存活對象。該階段是并發的,即應用線程和GC線程可以同時活動。并發標記耗時相對長很多,但因為不是STW,所以我們不太關心該階段耗時的長短。
  • 再標記階段:重新標記那些在并發標記階段發生變化的對象。該階段是STW的。

清理階段停頓分析

  • 清理階段清點出有存活對象的分區和沒有存活對象的分區,該階段不會清理垃圾對象,也不會執行存活對象的復制。該階段是STW的。

復制階段停頓分析

  • 復制算法中的轉移階段需要分配新內存和復制對象的成員變量。轉移階段是STW的,其中內存分配通常耗時非常短,但對象成員變量的復制耗時有可能較長,這是因為復制耗時與存活對象數量與對象復雜度成正比。對象越復雜,復制耗時越長。

四個STW過程中,初始標記因為只標記GC Roots,耗時較短。再標記因為對象數少,耗時也較短。清理階段因為內存分區數量少,耗時也較短。轉移階段要處理所有存活的對象,耗時會較長。

因此,G1停頓時間的瓶頸主要是標記-復制中的轉移階段STW。

#minorGC、majorGC、fullGC的區別,什么場景觸發full GC

在Java中,垃圾回收機制是自動管理內存的重要組成部分。根據其作用范圍和觸發條件的不同,可以將GC分為三種類型:Minor GC(也稱為Young GC)、Major GC(有時也稱為Old GC)、以及Full GC。以下是這三種GC的區別和觸發場景:

Minor GC (Young GC)

  • 作用范圍:只針對年輕代進行回收,包括Eden區和兩個Survivor區(S0和S1)。
  • 觸發條件:當Eden區空間不足時,JVM會觸發一次Minor GC,將Eden區和一個Survivor區中的存活對象移動到另一個Survivor區或老年代(Old Generation)。
  • 特點:通常發生得非常頻繁,因為年輕代中對象的生命周期較短,回收效率高,暫停時間相對較短。

Major GC

  • 作用范圍:主要針對老年代進行回收,但不一定只回收老年代。
  • 觸發條件:當老年代空間不足時,或者系統檢測到年輕代對象晉升到老年代的速度過快,可能會觸發Major GC。
  • 特點:相比Minor GC,Major GC發生的頻率較低,但每次回收可能需要更長的時間,因為老年代中的對象存活率較高。

Full GC

  • 作用范圍:對整個堆內存(包括年輕代、老年代以及永久代/元空間)進行回收。

  • 觸發條件

    • 直接調用System.gc()Runtime.getRuntime().gc()方法時,雖然不能保證立即執行,但JVM會嘗試執行Full GC。

    • Minor GC(新生代垃圾回收)時,如果存活的對象無法全部放入老年代,或者老年代空間不足以容納存活的對象,則會觸發Full GC,對整個堆內存進行回收。

    • 當永久代(Java 8之前的版本)或元空間(Java 8及以后的版本)空間不足時。

  • 特點:Full GC是最昂貴的操作,因為它需要停止所有的工作線程(Stop The World),遍歷整個堆內存來查找和回收不再使用的對象,因此應盡量減少Full GC的觸發。

#垃圾回收器 CMS 和 G1的區別?

區別一:使用的范圍不一樣:

  • CMS收集器是老年代的收集器,可以配合新生代的Serial和ParNew收集器一起使用
  • G1收集器收集范圍是老年代和新生代。不需要結合其他收集器使用

區別二:STW的時間:

  • CMS收集器以最小的停頓時間為目標的收集器。
  • G1收集器可預測垃圾回收?(opens new window)的停頓時間(建立可預測的停頓時間模型)

區別三: 垃圾碎片

  • CMS收集器是使用“標記-清除”算法進行的垃圾回收,容易產生內存碎片
  • G1收集器使用的是“標記-整理”算法,進行了空間整合,沒有內存空間碎片。

區別四: 垃圾回收的過程不一樣

img

注意這兩個收集器第四階段得不同

區別五: CMS會產生浮動垃圾

  • CMS產生浮動垃圾過多時會退化為serial old,效率低,因為在上圖的第四階段,CMS清除垃圾時是并發清除的,這個時候,垃圾回收線程和用戶線程同時工作會產生浮動垃圾,也就意味著CMS垃圾回收器必須預留一部分內存空間用于存放浮動垃圾
  • 而G1沒有浮動垃圾,G1的篩選回收是多個垃圾回收線程并行gc的,沒有浮動垃圾的回收,在執行‘并發清理’步驟時,用戶線程也會同時產生一部分可回收對象,但是這部分可回收對象只能在下次執行清理是才會被回收。如果在清理過程中預留給用戶線程的內存不足就會出現‘Concurrent Mode Failure’,一旦出現此錯誤時便會切換到SerialOld收集方式。

#什么情況下使用CMS,什么情況使用G1?

CMS適用場景:

  • 低延遲需求:適用于對停頓時間要求敏感的應用程序。
  • 老生代收集:主要針對老年代的垃圾回收。
  • 碎片化管理:容易出現內存碎片,可能需要定期進行Full GC來壓縮內存空間。

G1適用場景:

  • 大堆內存:適用于需要管理大內存堆的場景,能夠有效處理數GB以上的堆內存。
  • 對內存碎片敏感:G1通過緊湊整理來減少內存碎片,降低了碎片化對性能的影響。
  • 比較平衡的性能:G1在提供較低停頓時間的同時,也保持了相對較高的吞吐量。

#G1回收器的特色是什么?

G1 的特點:

  • G1最大的特點是引入分區的思路,弱化了分代的概念。
  • 合理利用垃圾收集各個周期的資源,解決了其他收集器、甚至 CMS 的眾多缺陷

G1 相比較 CMS 的改進:

  • 算法: G1 基于標記--整理算法, 不會產生空間碎片,在分配大對象時,不會因無法得到連續的空間,而提前觸發一次 FULL GC 。
  • 停頓時間可控: G1可以通過設置預期停頓時間(Pause Time)來控制垃圾收集時間避免應用雪崩現象。
  • 并行與并發:G1 能更充分的利用 CPU 多核環境下的硬件優勢,來縮短 stop the world 的停頓時間。

#GC只會對堆進行GC嗎?

JVM 的垃圾回收器不僅僅會對堆進行垃圾回收,它還會對方法區進行垃圾回收。

  1. 堆(Heap):?堆是用于存儲對象實例的內存區域。大部分的垃圾回收工作都發生在堆上,因為大多數對象都會被分配在堆上,而垃圾回收的重點通常也是回收堆中不再被引用的對象,以釋放內存空間。
  2. 方法區(Method Area):?方法區是用于存儲類信息、常量、靜態變量等數據的區域。雖然方法區中的垃圾回收與堆有所不同,但是同樣存在對不再需要的常量、無用的類信息等進行清理的過程。

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

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

相關文章

ubuntu服務器版啟動卡在start job is running for wait for...to be Configured

目錄 前言 一、原因分析 二、解決方法 總結 前言 當 Ubuntu 服務器啟動時,系統會顯示類似 “start job is running for wait for Network to be Configured” 或 “start job is running for wait for Plymouth Boot Screen Service” 等提示信息,并且…

Android 手寫簽名功能詳解:從原理到實踐

Android 手寫簽名功能詳解 1. 引言2. 手寫簽名核心實現:SignatureView 類3. 交互層實現:MainActivity 類4. 布局與配置5. 性能優化與擴展方向 1. 引言 在電子政務、金融服務等移動應用場景中,手寫簽名功能已成為提升用戶體驗與業務合規性的關…

【nRF9160 常用prj.conf配置與AT指令介紹】

參考資料: 技術討論:Q群:542294007 nRF91 NCS SDK安裝工具與SDK安裝包等常用軟件下載地址 云盤下載:pan.olib.cn 一、nRF9160 常用prj.conf配置介紹 nRF9160通過prj.conf配置網絡模式為:CAT-M模式 CONFIG_LTE_NETWOR…

小型化邊緣計算設備

以下是關于小型化邊緣計算設備的核心技術與應用特點的綜合分析: 一、核心硬件平臺與算力表現? NVIDIA Jetson Orin系列? Jetson Orin Nano?:配備1024個CUDA核心和32個Tensor核心,支持高達100 TOPS的AI算力,適用于機器人、無…

css使用clip-path屬性切割顯示可見內容

1. 需求 想要實現一個漸變的箭頭Dom&#xff0c;不想使用svg、canvas去畫&#xff0c;可以考慮使用css的clip-path屬性切割顯示內容。 2. 實現 <div class"arrow">箭頭 </div>.arrow{width: 200px;height: 60px;background-image: linear-gradient(45…

Kotlin與物聯網(IoT):Android Things開發探索

在物聯網&#xff08;IoT&#xff09;領域&#xff0c;Kotlin 憑借其簡潔性、安全性和與 Java 生態的無縫兼容性&#xff0c;逐漸成為 Android Things 開發的有力工具。盡管 Google 已于 2022 年宣布停止對 Android Things 的官方支持&#xff0c;但其技術思想仍值得探索&#…

2025年AI搜索引擎發展洞察:技術革新與市場變革

引言&#xff1a;AI搜索的崛起與市場格局重塑 2024-2025年&#xff0c;AI搜索市場迎來了前所未有的變革期。隨著DeepSeek-R1等先進大語言模型的推出&#xff0c;傳統搜索引擎、AI原生搜索平臺以及各類內容平臺紛紛加速智能化轉型&#xff0c;推動搜索技術從基礎信息檢索向深度…

基于 ESP32 與 AWS 全托管服務的 IoT 架構:MQTT + WebSocket 實現設備-云-APP 高效互聯

目錄 一、總體架構圖 二、設備端(ESP32)低功耗設計(適配 AWS IoT) 1.MQTT 設置(ESP32 連接 AWS IoT Core) 2.低功耗策略總結(ESP32) 三、云端架構(基于 AWS Serverless + IoT Core) 1.AWS IoT Core 接入 2.云端 → APP:WebSocket 推送方案 流程: 3.數據存…

【LeetCode 熱題 100】有效的括號 / 最小棧 / 字符串解碼 / 柱狀圖中最大的矩形

??個人主頁&#xff1a;小羊 ??所屬專欄&#xff1a;LeetCode 熱題 100 很榮幸您能閱讀我的文章&#xff0c;誠請評論指點&#xff0c;歡迎歡迎 ~ 目錄 棧有效的括號最小棧字符串解碼每日溫度柱狀圖中最大的矩形 堆數組中的第K個最大元素 棧 有效的括號 有效的括號 cl…

Petalinux

Petalinux 命令 參考《UG 1157 PetaLinux Command Line Reference Guide》 //創建petalinux工程 petalinux-create -t project --template zynq -n <name> //配置工程 cd 上一步的工程 petalinux-config --get-hw-description ../xsa_folder///配置Linux內核 petalinux-…

【Qt】在OrinNX上,使用命令安裝qtmultimedia5-dev時報錯

1、問題描述 在OrinNX+Ubuntu20.04上,使用命令安裝qtmultimedia5-dev時報錯 sudo apt install qtmultimedia5-devThe following packages have unmet dependencies: qtmultimedia5-dev : Depends: libpulse-dev but it is not going to be installed E: Unable to correct p…

上肢康復機器人設計與臨床應用研究

引言 腦卒中、脊髓損傷等神經系統疾病導致的上肢運動功能障礙&#xff0c;嚴重影響了患者的生活質量。傳統康復治療依賴治療師手動輔助訓練&#xff0c;存在效率低、量化難、人力成本高等問題。上肢康復機器人通過精準的運動控制與生物反饋機制&#xff0c;為實現高效、標準化…

mysql不能聚合之數據清洗逗號

有時候因為數據庫不嚴謹導致了出現有些數字很奇怪例如這樣是varchar類型的字符串&#xff0c; 這種數據不能用來運算聚合&#xff0c;那么要怎么辦呢&#xff1f; 這樣就搞定 REPLACE(your_column, ,, )??&#xff1a;將字段中的逗號移除&#xff0c;例如將3,553,850.28轉換…

chrome 瀏覽器插件 myTools, 日常小工具。

1. 起因&#xff0c; 目的: 比如&#xff0c;chatgpt, google&#xff0c; 打開網頁&#xff0c;就能直接輸入文字&#xff0c;然后 grok 就不行&#xff0c;必須用鼠標點一下&#xff0c;才能輸入文字。 對我而言&#xff0c;是個痛點&#xff01;寫個插件&#xff0c;自動點…

outbox架構解說

Outbox 模式是一種用于實現數據一致性的架構模式&#xff0c;特別是在微服務架構中。 它確保在處理事務時&#xff0c;數據的原子性和最終一致性。 Outbox 模式的詳細解說&#xff1a; 1. 概念與背景 背景&#xff1a;在微服務架構中&#xff0c;一個操作可能涉及多個服務&…

噴涂噴漆機器人詳解

1. 定義 噴涂噴漆機器人是專為表面涂裝設計的自動化工業設備&#xff0c;通過精準控制實現高效、均勻的涂料噴涂。其核心價值在于提升生產效率、保障質量一致性&#xff0c;同時減少材料浪費及環境污染&#xff0c;廣泛應用于汽車、航空航天等領域。 2. 結構組成 機械臂&…

DataX:一個開源的離線數據同步工具

DataX 是一個異構數據源離線同步&#xff08;ETL&#xff09;工具&#xff0c;實現了包括關系型數據庫(MySQL、Oracle 等)、HDFS、Hive、ODPS、HBase、FTP 等各種異構數據源之間穩定高效的數據同步功能。它也是阿里云 DataWorks 數據集成功能的開源版本。 為了解決異構數據源同…

微軟家各種copilot的AI產品:Github copilot、Microsoft copilot

背景 大家可能聽到很多copilot&#xff0c;比如 Github Copilot&#xff0c;Microsoft Copilot、Microsoft 365 Copilot&#xff0c;有什么區別 Github Copilot&#xff1a;有網頁版、有插件&#xff08;idea、vscode等的插件&#xff09;&#xff0c;都是面向于程序員的。Mi…

SpringMVC04所有注解按照使用位置劃分| 按照使用層級劃分(業務層、視圖層、控制層)

目錄 一、所有注解按照使用位置劃分&#xff08;類、方法、參數&#xff09; 1. 類級別注解 2. 方法級別注解 3. 參數級別注解 4. 字段/返回值注解 二、按照使用層級劃分&#xff08;業務層、視圖層、控制層&#xff09; 1、控制層&#xff08;Controller Layer&#x…

std::chrono類的簡單使用實例及分析

author: hjjdebug date: 2025年 05月 20日 星期二 14:36:17 CST descrip: std::chrono類的簡單使用實例及分析 文章目錄 1.實例代碼:2. 代碼分析:2.1 auto t1 std::chrono::high_resolution_clock::now();2.1.1 什么是 system_clock2.1.2 什么是 chrono::time_point?2.1.3 什…