【JVM 09-垃圾回收】

垃圾回收 筆記記錄

  • 1. 如何判斷對象可以回收
    • 1.1 引用計數法
      • 1.1.1 缺點
    • 1.2 可達性分析算法
      • 1.2.1 可達分析、根對象
      • 1.2.2 優缺點
    • 1.3 四種引用(強軟弱虛)
      • 1.3.1 軟引用的實際使用案例
      • 1.3.2 軟引用-引用隊列
      • 1.3.3 弱引用的實際使用案例
  • 2. 垃圾回收算法
    • 2.1 標記清除算法
    • 2.2 標記整理
    • 2.3 復制
  • 3. 分代垃圾回收
  • 4. 垃圾回收器
    • 4.1 吞吐量優先
    • 4.2 響應時間優先
  • 5. 垃圾回收調優

1. 如何判斷對象可以回收

下面介紹一些判斷對象是否可以被回收的算法。

1.1 引用計數法

基本原理

  1. 每個對象關聯一個計數器(整數),記錄當前有多少引用指向它。
  2. 引用增加時(如被變量賦值、被其他對象引用),計數器+1。
  3. 引用減少時(如變量離開作用域、被顯式置為null),計數器-1。
  4. 當計數器歸零,說明對象不再被任何引用指向,立即回收其內存。

1.1.1 缺點

引用計數法雖然簡單,但存在一個致命問題:無法解決循環引用。例如:

class A {B b;
}class B {A a;
}public class Main {public static void main(String[] args) {A a = new A(); // A 的引用計數 = 1B b = new B(); // B 的引用計數 = 1a.b = b; // B 的引用計數 = 2b.a = a; // A 的引用計數 = 2a = null; // A 的引用計數 = 1b = null; // B 的引用計數 = 1// 此時 A 和 B 互相引用,引用計數都不為 0,但已經無法訪問,造成內存泄漏!}
}

問題:

  1. 即使 a 和 b 已經不再被外部引用,但由于它們互相引用,引用計數仍然 > 0,導致無法回收,造成內存泄漏。
  2. Java 的解決方案:采用可達性分析(Reachability Analysis),從 GC Roots(如靜態變量、活動線程棧變量等)出發,標記所有可達對象,未被標記的則回收。

1.2 可達性分析算法

  1. 可達性分析算法(Reachability Analysis)是 Java 垃圾回收(GC)的核心算法,用于判斷對象是否存活。相比引用計數法,它能有效解決循環引用問題,是現代 JVM 采用的默認策略。
  2. 從一組「GC Roots」出發,遍歷所有能被引用的對象,未被遍歷到的即為垃圾。類似于“從樹根出發,標記所有可達的樹枝和樹葉,剩下的就是需要清理的枯枝”。
  3. 在這里插入圖片描述
  4. 肯定不能當成垃圾被回收的對象稱為根對象

1.2.1 可達分析、根對象

  • Java虛擬機中的垃圾回收器采用可達性分析來探索所有存活的對象。
  • 掃描堆中的對象,看是否能夠沿著GC Root對象為起點的引用鏈找到該對象,找不到,表示可以回收。
  • 哪些對象可以作為GC Root? 這里可以使用eclipse提供的MAT來找到
    在這里插入圖片描述
    MAT中有一個功能就是找到當前快照中的GC Roots
    在這里插入圖片描述
    GC Roots 構成:在這里插入圖片描述

jps 找到當前運行類的進程id
再配合jmap -dump:format=b,live,file=1.bin 21384
dump就是把堆內存當前運行的狀態轉儲成一個文件。
format表示轉儲文件的格式,b是二進制格式。
live會主動觸發一次垃圾回收,我們關注一次回收后還存活的對象。
file=1.bin 表示存儲的文件名稱。
21384就是jps看到的進程id.

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;/*** 通過Eclipse的MAT 查看哪些是GC Roots對象* */
public class Demo {public static void main(String[] args) throws IOException {List<Object> list=new ArrayList<>();list.add("a");list.add("b");System.out.println(1);System.in.read();list=null;System.out.println(2);System.in.read();System.out.println("end...");}
}

1.2.2 優缺點

這里是引用

1.3 四種引用(強軟弱虛)

  1. 強引用:默認的引用類型,只要強引用存在,對象就不會被 GC 回收。即使內存不足(OOM),JVM 也不會回收強引用對象,而是拋出 OutOfMemoryError。 通對象創建(如 String s = “hello”),我們平時寫代碼new xx()都屬于強引用。
  2. 軟引用:當 內存不足時,GC 會回收軟引用對象。適合實現 內存敏感的緩存(如圖片緩存)。
  3. 弱引用:只要發生 GC,無論內存是否充足,弱引用對象都會被回收。比軟引用更短暫,適合存儲 非必須的元數據。
  4. 虛引用:無法通過虛引用獲取對象(get() 始終返回 null)。
    唯一作用:對象被回收時收到系統通知(通過 ReferenceQueue)。
    必須與 ReferenceQueue 聯合使用。
  5. 其實還有一種,終結器引用:是一種與對象生命周期相關的特殊機制,它通過 finalize() 方法在對象被垃圾回收(GC)前提供一次“臨終拯救”機會。但因其設計缺陷,Java 9 開始已被標記為廢棄(@Deprecated),并建議使用更安全的替代方案(如 Cleaner)。
    在這里插入圖片描述

四種引用的對比在這里插入圖片描述
在這里插入圖片描述

1.3.1 軟引用的實際使用案例

這里設置堆內存是20m Xmx20m,對于某些圖片資源非核心業務,如果用強引用進行引用就會有可能導致內存溢出。這種不太重要的資源可以在內存緊張時將內存釋放掉,這種場景就可以使用軟引用。
下面代碼演示放入20m的對象,發現堆內存不夠直接OOM了,后面的例子使用軟引用就不會OOM。
在這里插入圖片描述

    private static final int _4MB=4*1024*1024;public static void main(String[] args) throws IOException {List<byte []> list=new ArrayList<>();for (int i=0;i<5;i++){list.add(new byte[_4MB]);}System.in.read();}

使用軟引用:內存不足時被回收
在這里插入圖片描述
前4個都被釋放了,只有最后1個byte數組還在。在這里插入圖片描述

    public static void soft(){// list -->SoftReference --> byte[]List<SoftReference<byte[]>> list=new ArrayList<>();for (int i=0;i<5;i++){SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);System.out.println(ref.get());list.add(ref);System.out.println(list.size());}System.out.println("循環結束:"+list.size());for (SoftReference<byte[]> softReference : list) {System.out.println(softReference.get());}}

1.3.2 軟引用-引用隊列

前面的演示我們發現,當使用軟引用的時候,可能前4個byte數組已經被釋放了,只保留了第5個在內存中。也就是最后遍歷list的時候很多元素都是null了,對這些軟引用對象,其實沒必要保留在list中了。這種情況我們希望把軟引用本身也做一個清理,既然釋放了,就把引用也清除掉。因為軟引用本身也要占用內存,盡管占用的相對較少。
如何清理無用的軟引用呢,就需要用到引用隊列。

    public static void soft() {List<SoftReference<byte[]>> list = new ArrayList<>();//引用隊列ReferenceQueue<byte[]> queue = new ReferenceQueue<>();for (int i = 0; i < 5; i++) {//關聯了引用隊列,當軟引用所關聯的byte[]被回收時,那么軟引用會被加入到引用隊列queue中去。SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB], queue);System.out.println(ref.get());list.add(ref);System.out.println(list.size());}System.out.println("循環結束:" + list.size());//獲取隊列中的軟引用Reference<? extends byte[]> poll = queue.poll();while (poll != null) {list.remove(poll);poll = queue.poll();}System.out.println("list中剩余的:===================>");for (SoftReference<byte[]> softReference : list) {System.out.println(softReference.get());}}

這時候看到list只有未被回收的byte數組。在這里插入圖片描述

1.3.3 弱引用的實際使用案例

這里可以看到第10次可能是因為軟弱引用本身也比較多了,發生了fullgc,前面幾次沒快超出堆內存時也會發發生了gc,所以又幾個null值。這里是引用

    public static void weak() {List<WeakReference<byte[]>> list = new ArrayList<>();//引用隊列ReferenceQueue<byte[]> queue = new ReferenceQueue<>();for (int i = 0; i < 10; i++) {WeakReference<byte[]> ref = new WeakReference<>(new byte[_4MB], queue);list.add(ref);for (WeakReference<byte[]> weakReference : list) {System.out.print(weakReference.get() + " ");}System.out.println();}}

2. 垃圾回收算法

2.1 標記清除算法

2.2 標記整理

2.3 復制

3. 分代垃圾回收

4. 垃圾回收器

4.1 吞吐量優先

4.2 響應時間優先

5. 垃圾回收調優

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

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

相關文章

《二叉搜索樹》

引言&#xff1a; 上次我們結束了類和對象的收尾&#xff0c;之后我們就要學習一些高級的數據結構&#xff0c;今天我們先來看一個數據結構-- 二叉搜索樹。 一&#xff1a; 二叉搜索樹的概念(性質) 二叉搜索樹又稱二叉排序樹&#xff0c;它或者是一棵空樹&#xff0c;或者是…

【Redis】Sentinel哨兵

&#x1f6e1;? 深入理解 Redis Sentinel&#xff1a;高可用架構的守護者 在實際開發中&#xff0c;我們常用 Redis 構建緩存系統或數據中間件。然而&#xff0c;主從復制雖然能實現數據同步&#xff0c;但無法自動故障轉移&#xff08;failover&#xff09;&#xff0c;這就…

Shell腳本應用及實戰演練

文章目錄 一、Shell腳本語言的基本結構1、Shell腳本的用途&#xff1a;2、 Shell腳本基本結構&#xff1a;3、 創建Shell腳本過程4、 腳本注釋規范 二、Shell腳本語言的變量用法詳解位置與預定義變量 三、 Shell字符串詳解1、Shell字符串拼接2、Shell字符串截取3、 Shell的格式…

軟件工程瀑布模型學習指南

軟件工程瀑布模型學習指南 一、瀑布模型核心概念 1.1 定義與特點 瀑布模型是一種經典的軟件開發流程,將項目劃分為順序性的階段,每個階段有明確的輸入和輸出,如同瀑布流水般單向推進。其特點包括: 階段間具有明確的順序性和依賴性強調文檔驅動和階段評審適合需求明確、穩…

獲取gitlab上項目分支版本(二)

獲取gitlab上項目分支版本_gitlab代碼分支版本在哪-CSDN博客 原先寫過一版&#xff0c;但是這次想更新一下項目的分支信息時&#xff0c;提示我 git服務器上的Python版本是2.7.3&#xff0c;這個錯誤表明當前Python環境中沒有安裝requests庫&#xff0c;服務器也沒有連接外網&…

主流防火墻策略繞過漏洞的修復方案與加固實踐

主流防火墻策略繞過漏洞的修復方案與加固實踐 流量關鍵點分析&#xff08;攻擊手法&#xff09; 攻擊者通過精心構造的TCP序列號攻擊和惡意標志組合繞過防火墻DPI檢測&#xff0c;核心手法如下&#xff1a; TCP連接建立&#xff08;正常握手&#xff09; 1049&#xff1a;客戶…

泛微OAe9-后端二開常見數據庫操作

泛微OAe9-后端二開常見數據庫操作 文章目錄 泛微OAe9-后端二開常見數據庫操作一、RecordSet1 RecordSet 操作OA本身的表2 RecordSet 操作OA 本身的存儲過程 二、RecordSetTrans三、RecordSetDataSource四、原生 jdbc 一、RecordSet RecordSet 適用于操作 OA 自己的庫。OA 數據庫…

【數據分析八:hypothesis testing】假設檢驗

本節我們講述假設檢驗和抽樣方法 有關假設檢驗的詳細內容&#xff0c;可以參考我以往的博客 概率論與數理統計總復習_概率論與數理統計復習-CSDN博客文章瀏覽閱讀1.5k次&#xff0c;點贊33次&#xff0c;收藏23次。中科大使用的教輔《概率論和數理統計》&#xff0c;帶大家復…

AI免費工具:promptpilot、今天學點啥、中英文翻譯

promptpilot 激發模型潛能&#xff0c;輕松優化 Prompt https://promptpilot.volcengine.com/startup 今天學點啥 https://metaso.cn/study 能生成網頁和語音播報 中英文翻譯 沉浸式翻譯&#xff0c;瀏覽器插件&#xff0c;ai翻譯

計算機網絡學習筆記:TCP三報文握手、四報文揮手

文章目錄 前言一、TCP三報文握手二、TCP四報文揮手三、TCP保活計時器 前言 TCP通信&#xff0c;通常需要經歷三個階段&#xff1a;三報文握手->發送&#xff0c;接收數據->四報文揮手。 一、TCP三報文握手 三報文握手處于TCP的連接建立階段&#xff0c;主要解決了以下的…

kafka部署和基本操作

一、部署kafka 解壓 tar xzvf kafka_2.12-3.9.1.tgz tar -zxf kafka_2.12-3.9.1.tgz 1.修改config/server.properties # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # …

Bootstrap 5學習教程,從入門到精通,Bootstrap 5 導航語法知識點及案例代碼(17)

Bootstrap 5 導航語法知識點及案例代碼 Bootstrap 5 提供了強大的導航組件&#xff0c;幫助開發者快速構建響應式且美觀的導航欄。 一、Bootstrap 5 導航組件概述 Bootstrap 5 提供了多種導航組件&#xff0c;主要包括&#xff1a; 導航欄&#xff08;Navbar&#xff09;&am…

清除 docker 無用的 鏡像/容器

清除 docker 無用的 鏡像/容器 刪除 <none> 的 docker 鏡像 使用以下命令刪除所有 的 Docker 鏡像&#xff08;即懸空鏡像 / dangling images&#xff09;&#xff1a; docker image prune -f這會自動刪除所有沒有 tag 的鏡像&#xff08;&#xff09;&#xff0c;不會…

使用Charles抓包工具提升API調試與性能優化效率

在軟件開發過程中&#xff0c;網絡請求調試和性能優化往往成為開發者遇到的挑戰&#xff0c;尤其是在進行API接口調試時。開發者需要確保網絡請求的正確性、響應時間以及系統的整體性能。然而&#xff0c;傳統的調試方法常常無法提供足夠的細節來深入分析問題&#xff0c;進而影…

如何協調各項目關鍵節點的沖突與依賴

在多項目并行的環境下&#xff0c;關鍵節點間的沖突與依賴是導致項目延期、資源浪費和溝通誤解的主要根源。要高效協調此類問題&#xff0c;企業應重點從建立透明的進度依賴圖、使用項目管理工具對齊節點、推動跨部門協同機制入手。其中&#xff0c;通過Gantt圖或關鍵路徑法實現…

mongodb單節點改副本集模式

前一陣將三節點的副本集改成了單節點&#xff0c;但后面業務代碼出現問題&#xff1a;無法使用事務&#xff0c;因為事務只有在副本集上能用&#xff0c;單節點無法使用&#xff0c;故需要改回副本集模式&#xff0c;而我目前僅有一臺服務器&#xff0c;所以考慮在一臺服務器上…

Android 修改了頁面的xml布局,使用了databinding,這時候編譯時需要用到apt嗎

deepseek回答&#xff1a; 在 Android 開發中使用 DataBinding 時&#xff0c;不需要顯式使用 apt&#xff08;Annotation Processing Tool&#xff09;。以下是詳細說明&#xff1a; 1. DataBinding 的編譯機制 DataBinding 是 Android Gradle 插件原生支持的功能&#xff…

服務器如何從http升級到https(nginx)

1.證書申請 可以到阿里云或者華為云去申請證書&#xff0c;申請完下載證書是個壓縮包&#xff0c;然后解壓 可以到到幾個文件夾&#xff0c;找到 .Nginx 文件夾打開 會有兩個文件&#xff0c;將這兩個文件上傳至nginx/conf/cert文件夾下&#xff08;cert需要手…

6.19_JAVA_微服務

1、跑后端的時候要把數據庫跑起來&#xff0c;否則會報錯。 2、predicate斷言&#xff1a; 預言&#xff1a;predict 3、gateway&#xff1a;出路口 4、API&#xff1a;List.of("a", "b", "c");把abc編程一個集合。 5、 6、shortcutFieldOrd…

Linux 基礎命令:`ls`、`cd`、`du` 快速入門

在 Linux 系統中&#xff0c;ls、cd 和 du 是日常操作中最常用的三個命令。掌握它們能大幅提升文件管理效率。 1. ls&#xff1a;查看目錄內容 用途&#xff1a;列出當前或指定目錄下的文件和子目錄。 常用命令&#xff1a; ls -l # 詳細列表&#xff08;權限、大…