深入理解JVM——垃圾回收與內存分配機制詳細講解

所謂垃圾回收,也就是要回收已經“死了”的對象。

那我們如何判斷哪些對象“存活”,哪些已經“死去”呢?

一、判斷對象已死

1、引用計數算法

給對象中添加一個引用計數器,每當有一個地方引用它時,計數器就加一;當引用失效時,計數器就減1;任何時刻計數器為0的對象就是不可能再被使用的。

但是在Java虛擬機里面沒有選用引用計數算法來管理內存。

優點:實現簡單,效率高。

缺點:很難解決對象之間相互循環引用的問題。

2、可達性分析算法

通過一系列的稱為“GC Roots”的對象作為起始點,從這些節點開始向下搜索,搜索走過的路徑稱為引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連(用圖論的話來說,就是從GC Roots到這個對象不可達)時,則證明此對象是不可用的。

如圖,object5、object6、object7 為可回收對象

主流的Java虛擬機使用可達性分析算法

關于GC Roots:

在Java語言中,GC Roots包括以下幾種:

  • 虛擬機棧(棧幀中的本地變量表)中引用的對象
  • 方法區中類靜態屬性引用的對象
  • 方法區中常量引用的對象
  • 本地方法棧中Native方法引用的對象

無論是通過引用計數算法判斷對象的引用數量,還是通過可達性分析算法判斷對象是否引用鏈可 達,判定對象是否存活都和“引用”離不開關系。

引用分為四種:

  • 強引用:代碼中普遍存在,垃圾收集器不會回收強引用的對象。比如new Object()
  • 軟引用:有用但非必需,在系統將要發生內存溢出異常OOM之前,會把這些對象列入回收范圍,進行回收。
  • 弱引用:非必需,無論當前內存是否足夠,下次垃圾回收都會回收掉這些對象。
  • 虛引用:最弱的引用關系,是否有虛引用不對其生存時間構成影響。相當于什么時候回收都沒問題,也無法通過虛引用來取得一個對象實例。為一個對象設置虛引用關聯的唯一目的只是為了能在這個對象被收集器回收時收到一個系統通知

二、三種垃圾回收算法

1、標記-清除算法

最基礎的收集算法——“標記-清除”(Mark-Sweep)算法。一般用于老年代

算法分為“標記”和“清除”兩個階段:

  1. 標記出需要回收的對象
  2. 清除被標記的對象

缺點:

  • 當有大量對象等待被回收,此時就需要大量的標記和清除操作,導致兩個過程的效率隨對象數量增長而降低,執行效率不穩定
  • 標記,清除后會產生大量不連續的內存碎片,導致空間碎片化問題

2、標記-復制算法

為了解決效率問題,標記-復制算法出現了。他將內存分為兩塊,每次只使用其中一塊,當一塊內存用完了,就將還存活的對象復制到另一塊上面,然后把已經使用過的內存空間一次性清理掉。

缺點:內存縮小為原來的一半。

但是在新生代的內存劃分中,研究表明,有98%的對象熬不過第一輪收集,因此沒必要采用1:1的內存劃分。針對這種情況,產生了半區分代策略。是把新生代分為一塊較大的Eden空間和兩塊較小的 Survivor空間,每次分配內存只使用Eden和其中一塊Survivor。發生垃圾搜集時,將Eden和Survivor中仍 然存活的對象一次性復制到另外一塊Survivor空間上,然后直接清理掉Eden和已用過的那塊Survivor空 間。HotSpot虛擬機默認Eden和Survivor的大小比例是8∶1?。如果另外一塊 Survivor空間沒有足夠空間存放上一次新生代收集下來的存活對象,這些對象便將通過分配擔保機制直 接進入老年代,這對虛擬機來說就是安全的。

3、標記-整理算法

在Mark-Sweep算法的基礎上做了改良,用于解決空間碎片化問題。標記-整理(Mark-Compact)算法在標記后不是簡單做清除,而是讓所有存活的對象都向一端移動,然后清理掉端邊界以外的內存。一般用于老年代。

優點:解決了空間碎片化問題,為后續內存分配和訪問提高效率

缺點:使內存回收的過程更加復雜。如果移動存活對象,尤其是在老年代這種每次回收都有大量對象存活區域,移動存活對象并更新所有引用這些對象的地方必須全程暫停用戶應用程序才能進行。

三、安全點和安全區域

安全點

在做可達性分析時,需要保持分析期間整個系統不會發生變化,這就導致GC進行時必須停頓所有Java執行線程(Stop The World),即使是在號稱(幾乎)不會發生停頓的CMS收集器中,枚舉根節點時也必須要停頓。

程序執行時并非在所有地方都能停下來開始GC,只有在到達安全點(Safepoint)時才能暫停。Safepoint 的選定既不能太少以致于讓GC等待時間太長,也不能過于頻繁以致于過分增大運行時的負荷。所以,安全點的選定基本上是以程序“是否具有讓程序長時間執行的特征”為標準進行選定的,例如方法調用,循環跳轉,異常跳轉等。

如何在GC發生時讓線程都跑到最近的安全點再停頓下來?

  • 搶先試中斷:先把所有線程中斷,發現不在安全點的線程恢復線程,讓它跑到安全點。
  • 主動式中斷:設置一個不可讀的內存位置作為中斷標志,標志與安全點重合,當線程執行到這個標志時自己中斷掛起。

安全區域

安全區域(Safe Region)是指在一段代碼片段中,引用關系不會發生變化。在這個區域的任何地方開始GC都是安全的。典型的安全區域比如線程處于Sleep狀態或者Blocked狀態。

在線程執行到Safe Region中的代碼時,首先標識自己已經進入了Safe Region。當要發起GC時,就不用管標識為Safe Region狀態的線程了。當線程要離開Safe Region時,要檢查是否處于GC狀態,如果是,就要繼續等待,直到收到可以安全離開Safe Region的信號為止。

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

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

相關文章

解決git reset --soft HEAD^撤銷commit時報錯

今天在使用git回退功能的時候,遇到以下錯誤: 解決git reset --soft HEAD^撤銷commit時報錯 問題: 在進行完commit后,想要撤銷該commit,于是使用了git reset --soft HEAD^命令,但是出現如下報錯&#xff1…

【學習心得】安裝cuda/cudann和pytorch

一、查看驅動信息 # 進入CMD輸入命令 nvidia-smi 也可以右下角圖標打開NVIDIA 設置進行查看 二、下載安裝CUDA 1、下載 下載地址 https://developer.nvidia.com/ 2、安裝 推薦自定義安裝。建議只勾選Cuda,只安裝這一個就好,以免報錯安裝失敗。 3、驗證…

移動端直播相關技術總結

一、直播APP原理 二、直播APP架構 三、直播APP實現流程 四、流媒體開發 流媒體模塊架構 流媒體相關基礎知識 幀:每一幀代表一幅靜止的圖像 GOP:Group of Pictures,畫面組,一個GOP就是一組連續的畫面,很多幀的集合 碼率…

BC136 KiKi去重整數并排序

給定一個整數序列,KiKi想把其中的重復的整數去掉,并將去重后的序列從小到大排序輸出。 輸入描述 第一行,輸入一個整數n,表示序列有n個整數。 第二行輸入n個整數(每個整數大于等于1,小于等于1000&#xf…

nodejs與前端js大文件、切片、視頻流相關技術示例

nodejs服務代碼 const express require("express"); const fs require("fs");const app express(); // 展示html頁面 app.get("/", function (req, res) {res.sendFile(__dirname "/index.html"); });// nodejs切片讀取文件示例 …

redis-配置詳解(基礎篇)

# 可以配置包含其他redis配置,可以使得配置更清晰化 # include /path/to/local.conf ################################## MODULES ##################################### # Load modules at startup. If the server is not able to load modules # it will abor…

拉丁方設計資料的方差分析(SPSS版+SAS版)

拉丁方設計(Latin square design):實驗研究中涉及一個處理因素和兩個控制因素,每個因素的類別數或水平數相等,此時可采用拉丁方設計,將兩個控制因素分別安排在拉丁方設計的行和列上。該設計類型仍為單因素方…

中電金信通過KCSP認證 云原生能力獲權威認可

中電金信通過KCSP(Kubernetes Certified Service Provider)認證,正式成為CNCF(云原生計算基金會)官方認證的 Kubernetes 服務提供商。 Kubernetes是容器管理編排引擎,底層實現為容器技術,是云原…

ABAP 新語法--Data Processing

1. String Template 新語法引入了字符串模板,用于處理字符串連接以及格式轉換 字符串模板在 | … | 之間定義,主要分為兩部分,固定文本和變量 其中,變量只能在 { … } 內使用,大括號之外的所有字符均作為固定文本使用…

【Swagger】只需要三步,就可以讓你的項目實現Swagger在線文檔,實時瀏覽,修改展示

目錄 1. pom.xml文件中添加Swagger的jar包 2. 配置Swagger 3. 項目啟動中加入Swagger注解的開關,啟動Swagger功能 4. 啟動項目,查看效果 Swagger 的功能這里就不多說明了,相信大家都懂的,好奇多問一句,大家有知道其…

zookeeper安裝配置采坑流程

安裝 wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.2/apache-zookeeper-3.8.2-bin.tar.gz解壓: tar -zxvf apache-zookeeper-3.8.2-bin.tar.gz如下 bin目錄下文件是可執行文件 conf目錄文件是配置文件 修改zoo.cfg(復制zoo_sample&#x…

從0搭建ECG深度學習網絡

本篇博客介紹使用Python語言的深度學習網絡,從零搭建一個ECG深度學習網絡。 任務 本次入門的任務是,篩選出MIT-BIH數據集中注釋為[‘N’, ‘A’, ‘V’, ‘L’, ‘R’]的數據作為本次數據集,然后按照8:2的比例劃分為訓練集&…

什么是DNS服務器的層次化和分布式?

DNS (Domain Name System) 的結構是層次化的,意味著它是由多個級別的服務器組成,每個級別負責不同的部分。以下是 DNS 結構的層次: 根域服務器(Root Servers): 這是 DNS 層次結構的最高級別。全球有13組根域…

【云原生】Docker 詳解(二):Docker 架構及工作原理

Docker 詳解(二):Docker 架構及工作原理 Docker 在運行時分為 Docker 引擎(服務端守護進程) 和 客戶端工具,我們日常使用各種 docker 命令,其實就是在使用 客戶端工具 與 Docker 引擎 進行交互。…

[oneAPI] 手寫數字識別-LSTM

[oneAPI] 手寫數字識別-LSTM 手寫數字識別參數與包加載數據模型訓練過程結果 oneAPI 比賽:https://marketing.csdn.net/p/f3e44fbfe46c465f4d9d6c23e38e0517 Intel DevCloud for oneAPI:https://devcloud.intel.com/oneapi/get_started/aiAnalyticsToolk…

Curson 編輯器

Curson 漢化與vacode一樣 Curson 自帶chat功能 1、快捷鍵ctrlk(代碼中編輯) 2、快捷鍵ctrll 右側打開窗口

為什么hive會出現_HIVE_DEFAULT_PARTITION分區

問題: 為什么hive表中出現_HIVE_DEFAULT_PARTITION分區? 解答: 因為在業務sql中使用的是動態分區,并且hive啟用動態分區時,對于指定的分區鍵如果存在空值時,會對空值部分創建一個默認分區用于存儲該部分…

小程序項目組件的基本應用

宿主環境:程序運行必須依賴的環境 小程序的宿主環境 ---->手機微信(定位、掃碼、支付等) 小程序的通信模型: 渲染層和邏輯層之間的通信(微信客戶端轉發)邏輯層和第三方服務器之間的通信(微信客戶端轉發) 小程序的運行機制: 啟動&#xff1…

c#實現工廠模式

可以使用以下代碼實現C#中的工廠模式: 首先,定義一個接口作為產品的抽象: public interface IProduct {void Operation(); }然后,創建具體的產品類: public class ConcreteProductA : IProduct {public void Operat…

vue基礎知識五:請描述下你對vue生命周期的理解?在created和mounted這兩個生命周期中請求數據有什么區別呢?

一、生命周期是什么 生命周期(Life Cycle)的概念應用很廣泛,特別是在政治、經濟、環境、技術、社會等諸多領域經常出現,其基本涵義可以通俗地理解為“從搖籃到墳墓”(Cradle-to-Grave)的整個過程在Vue中實…