JVM虛擬機系統性學習-對象存活判斷算法、對象引用類型和垃圾清除算法

垃圾回收

在 JVM 中需要對沒有被引用的對象,也就是垃圾對象進行垃圾回收

對象存活判斷算法

判斷對象存活有兩種方式:引用計數法、可達性分析算法

引用計數法

引用計數法通過記錄每個對象被引用的次數,例如對象 A 被引用 1 次,就將 A 的引用計數器加 1,當其他對象對 A 的引用失效了,就將 A 的引用計數器減 1

  • 優點:
    • 實現簡單,判定效率高
  • 缺點:
    • 需要單獨的字段存儲計數器,增加存儲空間開銷
    • 每次賦值都要更新計數器,增加時間開銷
    • 無法處理循環引用的情況,致命問題!即 A 引用 B,B 引用 A,那么他們兩個的引用計數器永遠都為 1

可達性分析算法

可達性分析算法可以有效解決循環引用的問題,Java 選擇了這種算法

可達性分析算法以根對象集合(GC Roots)為起使點,按照從上至下的方式搜索被根對象集合所連接的目標對象是否可達,通過可達性分析算法分析后,內存中的存活對象都會被根對象集合直接或間接連接著,搜索過程所走過的路徑稱為引用鏈,如果目標對象沒有任何引用鏈相連,則是不可達的,就可以標記為垃圾對象

GC Roots 主要包含以下幾類元素:

  • 虛擬機棧中引用的對象

    如:各個線程被調用的方法中所使用的參數、局部變量等

  • 本地方法棧內的本地方法引用的對象

  • 方法區中引用類型的靜態變量

  • 方法區中常量引用的對象

    如:字符串常量池里的引用

  • 所有被 synchronized 持有的對象

  • Java 虛擬機內部的引用

    如:基本數據類型對應的 Class 對象、異常對象(如 NullPointerException、OutOfMemoryError)、系統類加載器

垃圾回收過程

在 Java 中對垃圾對象進行回收需要至少經歷兩次標記過程:

  • 第一次標記:如果經過可達性分析后,發現沒有任何引用鏈相連,則會第一次被標記
  • 第二次標記:判斷第一次標記的對象是否有必要執行 finalize() 方法,如果在 finalize() 方法中沒有重新與引用鏈建立關聯,則會被第二次標記

第二次被標記成功的對象會進行回收;否則,將繼續存活

對象的 finalization 機制:

Java 提供了 finalization 機制來允許開發人員 自定義對象被銷毀之前的處理邏輯,即在垃圾回收一個對象之前,會先調用這個對象的 finalize() 方法,該方法允許在子類中被重寫,用于在對象被回收時進行資源釋放的工作

對象引用

在 JDK1.2 之后,Java 對引用的概念進行了擴張,將引用分為強引用(StrongReference)、軟引用(SoftReference)、弱引用(WeakReference)、虛引用(PhantomReference)四種,這四種引用強度依次逐漸減弱

  • 強引用-不回收:強引用是最普遍的對象引用,也是默認的引用類型,強引用的對象是可觸及的,垃圾回收器永遠不會回收被引用的對象,因此強引用是造成Java內存泄漏的主要原因之一

    • 當使用new操作創建一個新對象時,并且將其賦值給一個變量時,這個變量就成為該對象的一個強引用
  • 軟引用-內存不足回收:在即將發生內存溢出時,會將這些對象列入回收范圍進行第二次回收,如果回收之后仍然沒有足夠的內存,則會拋出內存溢出異常

    • 軟引用通常用來實現內存敏感的緩存,例如高速緩存使用了軟引用,如果內存足夠就暫時保留緩存;如果內存不足,就清理緩存

      // 創建弱引用
      SoftReference<User> softReference = new SoftReference<>(user);
      // 從軟引用中獲取強引用對象
      System.out.println(softReference.get());
      
  • 弱引用-發現即回收:被弱引用關聯的對象只能存活在下一次垃圾回收之前,在垃圾回收時,無論空間是否足夠,都會會受掉被弱引用關聯的對象

    • 弱引用常用于監控對象是否已經被垃圾回收器標記為即將回收的垃圾,可以通過弱引用的 isEnQueued 方法判斷對象是否被垃圾回收器標記

      Object obj = new Object();
      WeakReference<Object> wf = new WeakReference<Object>(obj);
      obj = null;
      // System.gc();
      // 有時候會返回null
      Object o = wf.get(); 
      // 返回是否被垃圾回收器標記為即將回收的垃圾
      boolean enqueued = wf.isEnqueued(); 
      System.out.println("o = " + o);
      System.out.println("enqueued = " + enqueued);
      
  • 虛引用:垃圾回收時,直接回收,無法通過虛引用獲取對象實例

    • 為一個對象設置虛引用關聯的唯一目的就是能在這個對象被垃圾回收時收到一個系統通知

      Object obj = new Object();
      PhantomReference<Object> pf = new PhantomReference<Object>(obj, new
      ReferenceQueue<>());
      obj=null;
      // 永遠返回null
      Object o = pf.get();
      // 返回是否從內存中已經刪除
      boolean enqueued = pf.isEnqueued();
      System.out.println("o = " + o);
      System.out.println("enqueued = " + enqueued);
      

垃圾清除算法

GC最基礎的算法有三種: 標記 -清除算法、復制算法、標記-壓縮算法,我們常用的垃圾回收器一般都采用分代收集算法。

  • 標記-清除算法:在標記階段,從 GC Roots 開始遍歷,標記所有被引用的對象,標記為可達對象,再對堆內存從頭到尾遍歷,回收沒有標記為可達對象的對象(標記清除算法可以標記存活對象也可以標記待回收對象)

    • 這里并不是真正清除,而是將清除對象的地址放在空閑的地址列表中
    • 缺點
      • 效率不高
      • GC 時需要停止整個應用進程,用戶體驗不好
      • 會產生內存碎片

    在這里插入圖片描述

  • 復制算法:它將可用內存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活著的對象復制到另外一塊上面,然后再把已使用過的內存空間一次清理掉

    現在商用的 Java 虛擬機大多都優先采用這種收集算法去回收新生代,如果將內存區域劃分為容量相同的兩部分太占用空間,因此將復制算法進行了優化,優化后將新生代分為了 Eden 區、Survivor From 區、Survivor To 區,Eden 和 Survivor 的大小比例為 8:1:1,每次分配內存時只使用 Eden 和其中的一塊 Survivor 區,在進行垃圾回收時,將 Eden 和已經使用過的 Survivor 區的存活對象轉移到另一塊 Survivor 區中,再清理 Eden 和已經使用過的 Survivor 區域,當 Survivor 區域的空間不足以容納一次 Minor GC 之后存活的對象時,就需要依賴老年代進行分配擔保(通過分配擔保機制,將存活的對象放入老年代即可)

    • 優點
      • 實現簡單,運行高效
      • 復制之后,保證空間的連續性,不會出現“內存碎片”
    • 缺點
      • 存在空間浪費
    • 應用場景
      • 在新生代,常規的垃圾回收,一次可以回收大部分內存空間,剩余存活對象不多,因此現在的商業虛擬機都是用這種收集算法回收新生代

    在這里插入圖片描述

  • 標記-壓縮算法:標記過程仍然與“標記-清除”算法一樣,之后將所有的存活對象壓到內存的一端,按順序排放,之后,清理邊界外的內存

    • 優點
      • 解決了標記-清除算法出現內存碎片的問題
      • 解決了復制算法中空間浪費的問題
    • 缺點
      • 效率上低于復制算法
      • 移動對象時,如果對象被其他對象引用,則還需要調整引用的地址
      • 移動過程中,需要暫停用戶應用程序。即 STW

    在這里插入圖片描述

  • 分代收集算法:把 Java 堆分為新生代和老年代,這樣就可以對不同生命周期的對象采取不同的收集方式,以提高回收效率

    當前商業虛擬機都采用這種算法

    • 新生代中的對象生命周期短,存活率低,因此適合使用復制算法(存活對象越少,復制算法效率越高)
    • 老年代中對象生命周期長,存活率高,回收沒有新生代頻繁,一般使用標記-清除或者是標記-壓縮

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

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

相關文章

c#面試基礎語法——現有?個整數number,請寫?個?法判斷這個整數是否是2的N次?

1.number%20 取余&#xff08;取模&#xff09;只能判斷number是不是2的倍數但不一定是2的N次方&#xff0c;如&#xff1a;6%20但是他并不是2的N次方 2.(number&(number-1))0 原理&#xff1a;如果number是2的N次方則表示2進制位只有一位是1。如&#xff1a;2 &#xff08…

多示例VS多標簽VS多示例多標簽-week2

一、多示例 多示例學習屬于弱監督學習中的一種&#xff0c;在對模型進行訓練時&#xff0c;我們需要把訓練數據分成正負包&#xff0c;再將每個包分成大小相同的示例&#xff0c;并且我們只對包的正負進行標注&#xff0c;而不對示例進行分類。當某個包被標識為正時&#xff0c…

Java怎么實現動態代理?

Java怎么實現動態代理&#xff1f; Java中實現動態代理主要依賴于java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler接口。動態代理可以用于在運行時創建代理類及其實例。以下是一個簡單的動態代理示例&#xff1a; 首先&#xff0c;定義一個接口&#xff1a;…

Python常見面試知識總結(二):數據結構、類方法及異常處理

【十三】Python中assert的作用&#xff1f; Python中assert&#xff08;斷言&#xff09;用于判斷一個表達式&#xff0c;在表達式條件為 f a l s e false false的時候觸發異常。 斷言可以在條件不滿足程序運行的情況下直接返回錯誤&#xff0c;而不必等待程序運行后出現崩潰…

光伏設計方案:實現清潔能源的未來

隨著全球氣候變化和能源需求日益增長的問題日益嚴重&#xff0c;光伏發電作為一種清潔、可再生的能源形式&#xff0c;正逐漸成為全球能源轉型的主力軍。而在光伏發電技術的廣泛應用中&#xff0c;一個優秀的光伏設計方案對于實現高效、穩定和安全的發電目標至關重要。 光伏設…

【項目管理】如何用思維導圖做計劃?

思維導圖是一種可視化的思維工具&#xff0c;它可以讓我們的思考過程變得很直觀。它可以幫助我們考慮到計劃的各個方方面面&#xff0c;確定各要素之間的關系。 思維導圖總結功能很強&#xff0c;完成計劃后&#xff0c;可以用思維導圖進行總結&#xff0c;為下一次做計劃積累…

Linux中tar命令詳解

具體用法 tar命令是Linux中用于打包和壓縮文件或目錄的命令&#xff0c;常用于備份和歸檔。它可以將多個文件或目錄打包成一個單一的文件&#xff0c;并可以選擇是否壓縮打包文件。 打包文件或目錄 tar -cvf archive.tar file1 file2 directory1上面的命令將file1、file2和dir…

使用【ShardingSphere】分庫分表

前言 ShardingSphere可以支撐分庫分表&#xff0c;剛果商城采用了垂直分庫&#xff08;根據不同業務拆分數據庫&#xff09;&#xff0c;因此此文章只演示水平分表。 垂直分庫 不同業務拆分為不同的數據庫&#xff08;例如商城業務&#xff09; 水平分表 分表可以通過將大表拆…

2024年軟考高項還是機考嗎?附常見問題答疑

2024年軟考高項實行機考&#xff08;三科均為機考&#xff0c;綜合知識考試時間為上午8:30-11:00&#xff0c;案例論文聯考&#xff0c;考試時間為下午14:30-18:00&#xff09;&#xff0c;本文為大家整理了一些機考常見問題&#xff0c;希望對大家有所幫助。 一、軟考高項機考…

React Hooks學習指北

一、前言 在當今的前端開發環境中&#xff0c;越來越多的開發者認可了 Hooks 的強大能力&#xff0c;并紛紛加入到 Hooks 的使用大軍中&#xff1a; 2019 年 2 月&#xff0c;React 正式發布 v16.8 版本&#xff0c;引入 Hooks 能力&#xff08;最新的 v18 中&#xff0c;還新…

移液器吸頭材質選擇——PFA吸頭在半導體化工行業的應用

PFA吸頭是一種高性能移液器配件&#xff0c;這種材料具有優異的耐化學品、耐熱和電絕緣性能&#xff0c;使得PFA吸頭在應用中表現出色。那么它有哪些特點呢&#xff1f; 首先&#xff0c;PFA吸頭具有卓越的耐化學腐蝕性能。無論是酸性溶液、堿性溶液還是有機溶劑&#xff0c;P…

如何用CHAT幫你提高工作效率?

問CHAT&#xff1a;從規范項目管理流程交付&#xff0c;分別對項目信息安全管理&#xff0c;項目預算管理和項目采購管理三個方面提建議 CHAT回復&#xff1a; 項目信息安全管理: 1. 制定詳細的信息安全政策&#xff0c;所有參與項目的員工必須遵守&#xff0c;對其中涉及敏感…

wpf TelerikUI使用DragDropManager

首先&#xff0c;我先創建事務對象ApplicationInfo&#xff0c;當暴露出一對屬性當例子集合對于構成ListBoxes。這個類在例子中顯示如下代碼&#xff1a; public class ApplicationInfo { public Double Price { get; set; } public String IconPath { get; set; } public …

亞馬遜S3V4驗簽與MINIO驗簽區別

1、先看下官方文檔 AWS S3V4 DEMO 2、實際調用試試 1&#xff09;代碼 // 計算auth// for a simple GET, we have no body so supply the precomputed empty hashMap<String, String> headers new HashMap<String, String>();headers.put("x-amz-content…

0013Java安卓程序設計-ssm酒品移動電商平臺app

文章目錄 **摘要**目錄系統實現5.1 APP端5.2管理員功能模塊開發環境 編程技術交流、源碼分享、模板分享、網課分享 企鵝&#x1f427;裙&#xff1a;776871563 摘要 首先,論文一開始便是清楚的論述了系統的研究內容。其次,剖析系統需求分析,弄明白“做什么”,分析包括業務分析…

Firewalld 防火墻配置

文章目錄 Firewalld 防火墻配置1. Firewalld 概述2. 區域名稱及策略規則3. Firewalld 配置方法4. Firewalld 參數和命令5. Firewalld 兩種模式6. Firewalld 使用 Firewalld 防火墻配置 1. Firewalld 概述 firewalld 是一個動態防火墻管理器&#xff0c;作為 Systemd 管理的防…

【docker】常用命令

啟動docker服務 systemctl start docker 停止docker服務 systemctl stop docker 重啟docker服務 systemctl restart docker 查看docker服務狀態 systemctl status docker 設置開機啟動docker服務 systemctl enable docker 設置關閉開機啟動docker服務 systemctl disable …

數據在內存中的存儲(浮點型篇)

1.例子&#xff1a;5.5&#xff1a;內存存儲為101.1&#xff0c;十分位百分位依次為2的-1次方&#xff0c;2的-2次方&#xff0c;而使用科學計數法可以改寫為1.011*2的2次方 2.國際標準公式&#xff1a;-1的D次方*M*2的E次方&#xff0c;x1負0正 3.M在存儲時默認整數部分為1&…

使用Spring Boot和領域驅動設計實現模塊化整體

用模塊化整體架構編寫的代碼實際上是什么樣的&#xff1f;借助 Spring Boot 和 DDD&#xff0c;我們踏上了編寫可維護和可演化代碼的旅程。 當談論模塊化整體代碼時&#xff0c;我們的目標是以下幾點&#xff1a; 應用程序被組織成模塊。每個模塊解決業務問題的不同部分。模塊…