JVM(2)--一文讀懂垃圾回收

與其他語言相比,例如c/c++,我們都知道,java虛擬機對于程序中產生的垃圾,虛擬機是會自動幫我們進行清除管理的,而像c/c++這些語言平臺則需要程序員自己手動對內存進行釋放。

雖然這種自動幫我們回收垃圾的策略少了一定的靈活性,但卻讓代碼編寫者省去了很多工作,同時也提高了很多安全性。(因為像C/C++假如你創建了大量的對象,但卻由于自己的疏忽忘了將他們進行釋放,可能會造成內存溢出)。

何為垃圾?

剛才說了,虛擬機會自動幫助我們進行垃圾的清除,那什么樣的對象我們才可以稱為是垃圾對象呢?

假如你創建了一個對象

Man m = new Man();

你用一個變量指向了這個對象,顯然對于這個對象,你可以用變量m對這個對象進行利用,但過了一段時間,你執行了

m = null;

并且也并沒有新的變量來指向剛才創建的對象。此時對于這個沒有任何變量指向的對象,你覺得它還有用處嗎?

顯然,對于這種沒有被變量指向的對象,它是一點卵用也沒有的,它只能在隨風漂流。

因此,對于這樣的對象,我們就可以把它稱為垃圾了,它早晚會被垃圾回收器給干掉。

怎么知道它已經是垃圾對象了?

假如代碼是你自己編寫的,你可能知道這個對象啥時候應該被拋棄,你可以隨時讓它成為垃圾對象。

但是,你畢竟是你,虛擬機則沒那么智能。那虛擬機是如何知道的呢?

上面已經說了,沒有變量引用這個對象時,它就是垃圾對象了,基于這個原理,我們可以這樣做啊:

我們可以為這個對象設置一個計數器,初始值為0,假如有一個變量指向它,那么計數器就加1,如果這個變量不在指向它了,計數器就減1。那么我們就可以判斷,如果這個計數器為0的話,那它就是垃圾對象了,否則就是有用的對象。

對于這種方法,我們稱之為引用計數法

好吧,我們先來夸一夸引用計數法這種方法:

  1. 實現簡單。
  2. 效率高(一個if語句就能解決的問題想不高效都難)。

不好意思,接下來得說說它那個致命的缺點

實際上,對于這種引用計數的方法,假如它遇到對象互相引用的話,是很難解決的。

先看一段代碼:

Man m1 = new Man();
Man m2 = new Man();
//互相引用
m1.instance = m2;//假設Man有instance這個屬性
m2.instance = m1;m1 = null;
m2 = null;
System.gc();//按道理對象應該被回收

這段代碼m1和m2都指向null了,按道理兩個對象已經是無用對象,應該被回收,但是,兩個對象之間彼此有一個instance的屬性互相牽引的對方,導致兩個對象并沒有被回收。

這個缺點夠致命吧?

所以,虛擬機并沒有采用這種引用計數的方法。

可達性分析

除了這種方法,我們還有其他的方法嗎?

答案是有的,必須得有啊。這種方法就是傳說中的可達性分析,(我靠,聽名字是真的高級啊)。它的工作原理是這樣的:

在程序開始時,會建立一個引用根節點(GC Roots),并構建一個引用圖。當需要判斷誰是垃圾時,我們可以從這個根節點進行遍歷,如果沒有被遍歷到的節點則是垃圾對象,否則就是有用對象。如下圖:

這個方法可以解決循環相互引用的問題,但是這個方法并沒有引用計數法高效,畢竟要遍歷圖啊。

總結下判斷是否為垃圾對象的算法:

  1. 引用計數法。
  2. 可達性分析。

何時進行垃圾回收

可能有人會覺得這個問題很奇怪,覺得看到垃圾就回收不是很好。對于這個我只能說:

  1. 看到房間有一點垃圾你會馬上掃?還是等到某個時間點或者當垃圾積累到一定的數量再掃?
  2. 虛擬機可沒那么智能可以馬上識別這個對象是垃圾對象,它還得遍歷所有對象才能知道有哪些是垃圾對象。

所以說,你總不能幾秒(我們假設幾秒是賊短的時間)就讓虛擬機遍歷一下所有對象吧?

這里先說明一下,當垃圾回收器在進行垃圾回收的時候,為了保證垃圾回收不受干擾,是會暫停所有線程的,此時程序無法對外部的請求進行響應。(因為你想啊,當你在可達性分析的時候,那些引用關系還在不斷著變化,那不很難受)。

而且頻繁的垃圾回收,對于有一些程序,是很影響用戶體驗的,例如你在玩游戲,系統動不動就停頓一下,怕你是要把這游戲給刪了。

所以說,垃圾回收是會等到內存被使用了一定的比例的時候,才會觸發垃圾回收。至于這個比例是多少,這可能就是人為規定的了。

怎么回收?

當我們標記好了哪些是垃圾,想要進行回收的時候,該怎么回收比較好呢?

可能有一些人就覺得奇怪,這還不簡單,看見它是垃圾,直接回收不就得了。

其實這也不無道理,簡單粗暴,直接回收。

是的,確實有這樣的算法,看哪些是被我們標記的垃圾,看見了就直接回收。這種算法我們稱之為標記--清除算法

標記-清除算法工作原理:就是先標記出所有需要回收的對象,然后在統一回收所有被標記過的對象。

不過,那些人你可別得意啊,因為這種方法雖然簡單暴力,但它有個致命的缺點就是:

標記清除過后,會產生大量的不連續內存碎片,如果不連續的碎片過多的話,,可能會導致有一些大的對象存不進去。這樣,會導致下面兩個問題:

  1. 有些內存浪費了。
  2. 對象存不進去,會又一次觸發垃圾回收。

復制算法

為了解決這種問題,另外一種算法出現了---復制算法。就是說,它會將可用的內存按容量劃分成兩塊。然后每次只使用其中的一塊,當這一塊快用完的時候,就會觸發垃圾回收,它會把還存活的對象全部復制到另外一塊內存中去,然后把這塊內存全部清理了。

這樣,就不會出現碎片問題了。

居然幫我們解決了我們必須夸一下它:不僅幫我們解決了問題,而且實現上也簡單、運行也高效。

但是(凡事都有個但是的),它也是有缺點的,缺點很明顯,發現了沒有。假如每次存活的對象都很少很少,那另外一塊內存不是幾乎沒有用到?所以說,這種方法有可能導致另外一半內存幾乎沒用了。內存那么寶貴,這可是很嚴重的問題。

優化策略:可以告訴你,有研究顯示,其實有98%的對象都是朝生夕死的,也就是說,每次存活的對象確實很少很少。既然我們都知道存活的對象很少很少了,那我們干嘛還1:1的比例來分配?所以說,HotShot虛擬機是默認按8:1的比例來分配的。這樣,就不會出現很多內存沒用到的問題了。

可能有人會說,萬一占比為1/9的內存不夠用了怎么辦?不就沒地方存那些活的對象?實際上,當內存不夠用時,可以向其他地方借些內存來使用,例如老年代里的內存。

這里說明一下新生代和老年代:說白了,新生代就是剛剛創建不久的對象,而老年代是已經活了挺久的對象。也就是說,有一些對象是確實活的比較久的,對于這種對象,我們另外給它分配內存來養老,而且垃圾回收時,我們不用每次都來這里查找有沒垃圾對象,因為這些對象是垃圾的幾率會比較小。

下面在簡單介紹另外兩種算法:

  1. 標記-整理算法:這種算法和標記-清除算法類似,不過它把垃圾清除了之后,會讓存活的對象往一個方向靠攏,以此來整理碎片。
  2. 分代收集算法:所謂分代就是把對象分成類似上面說的老年代和新生代,在新手代一般每次垃圾回收時死的對象一般都會比較多,而老年代會比較少,基于這種關系,我們就可以采取不同的算法來針對了。

總結下垃圾回收的幾種算法:

  1. 標記-清除算法。
  2. 復制算法。
  3. 標記-整理算法。
  4. 分代收集算法。

最后給大家幾種垃圾回收器

對于垃圾的回收,你是想一邊運行程序其他代碼一邊進行垃圾回收?還是想把垃圾全收好再來執行程序的其他代碼?雖然說最終使用cpu的時間是一樣,但兩種方式還是有區別的。

下面簡單介紹幾種垃圾回收器,看看他們都使用哪種方。

(1).Serial收集器

serial(串行),看這個英文單詞就知道這是一個單線程收集器。也就是說,它在進行垃圾回收時,必須暫停其他所有線程。顯然,有時垃圾回收停頓的比較久的話,這對于用戶來說是很難受的。

(2).ParNew

這個收集器和Serial很類似,進行垃圾回收的時候,也是得暫停其他所有線程,不過,它可以多條線程工作進行垃圾回收。

(3).Parallel Scavenge收集器

parallel,并行的意思。也是可以多線程進行垃圾回收處理,但是它與ParNew不同。它會嚴格控制垃圾回收的時間與執行其他代碼的時間之間的比例。我們來看一個名詞:吞吐量

吞吐量 = 運行用戶代碼時間 / (運行用戶代碼時間 + 垃圾收集時間)。

也就是說,Parallet Scavenge收集器會嚴格控制吞吐量,至于這個吞吐量是多少,這個可以人為設置。

下面兩個收集器重點介紹下

(4).CMS(Concurrent Mark Sweep)收集器

CMS收集器是基于“標記-清除”算法實現的,它的運作過程相對于前面幾種收集器來說要更復雜一些,整個過程分為4個步驟,包括:

  1. 初始標記(CMS initial mark)
  2. 并發標記(CMS concurrent mark)
  3. 重新標記(CMS remark)
  4. 并發清除(CMS concurrent sweep)

其中初始標記、重新標記這兩個步驟仍然需要暫停其他線程。但另外兩個步驟可以和其他線程并發執行。初始標記僅僅只是標記一下GCRoots能直接關聯到的對象,速度很快,并發標記階段就是進行GC Roots Tracing的過程 (說白了就是把整個圖都遍歷了,找出沒有的對象)

而重新標記階段則是為了修正并發標記期間,因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄,這個階段的停頓時間一般會比初始標記階段稍長一些,但遠比并發標記的時間短。

由于整個過程中耗時最長的并發標記和并發清除過程中,收集器線程都可以與用戶線程一起工作,所以總體上來說,CMS收集器的內存回收過程幾乎是與與用戶線程一起并發地執行。

(5).G1收集器

這個估計是最牛的收集器了。該收集器具有如下特點:

  1. 并行與并發:G1能充分利用現代計算器多CPU,多核的硬件優勢,可以使用并發或并行的方式來縮短讓其他線程暫停的優勢。
  2. 分代收集:就是類似像分出新生代和老年代那樣處理。
  3. 空間整合:采用了復制算法+標記-整合算法的特點來回收垃圾。就是整體采用標記-整理算法,局部采用復制算法
  4. 可預測停頓:這個就牛了,就是說,它能讓使用者明確指定在一個長度為M毫秒的時間片段內,消耗在垃圾收集上的時間不超過N毫秒。

它的執行過程大體如下:

  1. 初始標記。
  2. 并發標記。
  3. 最終標記。
  4. 篩選回收。

這個流程和CMS很相似,它也是在初始標記最終標記需要暫停其他線程,但其他兩個過程就可以和其他線程并發執行。

剛才我們說了G1收集器哪些優點,例如可預測停頓,這也使得篩選回收,是可以預測停頓垃圾回收的時間的,也就是說,停頓的時間是用戶自己可以控制的,這也使得一般情況下,在篩選回收的時候,我們會暫停其他線程的執行,把所有時間都用到篩選回收上。

本次講解到這里。

關注公我的眾號:苦逼的碼農,獲取更多原創文章,后臺回復"禮包"送你一份特別的資源大禮包。

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

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

相關文章

2058. 找出臨界點之間的最小和最大距離

2058. 找出臨界點之間的最小和最大距離 鏈表中的 臨界點 定義為一個 局部極大值點 或 局部極小值點 。 如果當前節點的值 嚴格大于 前一個節點和后一個節點,那么這個節點就是一個 局部極大值點 。 如果當前節點的值 嚴格小于 前一個節點和后一個節點,…

tb計算機存儲單位_如何節省數TB的云存儲

tb計算機存儲單位Whatever cloud provider a company may use, costs are always a factor that influences decision-making, and the way software is written. As a consequence, almost any approach that helps save costs is likely worth investigating.無論公司使用哪種…

nginx簡單代理配置

原文:https://my.oschina.net/wangnian/blog/791294 前言 Nginx ("engine x") 是一個高性能的HTTP和反向代理服務器,也是一個IMAP/POP3/SMTP服務器。Nginx是由Igor Sysoev為俄羅斯訪問量第二的Rambler.ru站點開發的,第一個公開版本…

2059. 轉化數字的最小運算數

2059. 轉化數字的最小運算數 給你一個下標從 0 開始的整數數組 nums ,該數組由 互不相同 的數字組成。另給你兩個整數 start 和 goal 。 整數 x 的值最開始設為 start ,你打算執行一些運算使 x 轉化為 goal 。你可以對數字 x 重復執行下述運算&#xf…

Django Rest Framework(一)

一、什么是RESTful REST與技術無關,代表一種軟件架構風格,REST是Representational State Transfer的簡稱,中文翻譯為“表征狀態轉移”。 REST從資源的角度審視整個網絡,它將分布在網絡中某個節點的資源通過URL進行標識&#xff0c…

光落在你臉上,可愛一如往常

沙沙野 https://www.ssyer.com讓作品遇見全世界圖片來自:沙沙野沙沙野 https://www.ssyer.com讓作品遇見全世界圖片來自:沙沙野沙沙野 https://www.ssyer.com讓作品遇見全世界圖片來自:沙沙野沙沙野 https://www.ssyer.com讓作品遇見全世界圖…

數據可視化機器學習工具在線_為什么您不能跳過學習數據可視化

數據可視化機器學習工具在線重點 (Top highlight)There’s no scarcity of posts online about ‘fancy’ data topics like data modelling and data engineering. But I’ve noticed their cousin, data visualization, barely gets the same amount of attention. Among dat…

2047. 句子中的有效單詞數

2047. 句子中的有效單詞數 句子僅由小寫字母(‘a’ 到 ‘z’)、數字(‘0’ 到 ‘9’)、連字符(’-’)、標點符號(’!’、’.’ 和 ‘,’)以及空格(’ )組成。…

fa

轉載于:https://www.cnblogs.com/smallpigger/p/9546173.html

python中nlp的庫_用于nlp的python中的網站數據清理

python中nlp的庫The most important step of any data-driven project is obtaining quality data. Without these preprocessing steps, the results of a project can easily be biased or completely misunderstood. Here, we will focus on cleaning data that is composed…

51Nod 1043 幸運號碼

1 #include <stdio.h>2 #include <algorithm>3 using namespace std;4 5 typedef long long ll;6 const int mod 1e9 7;7 int dp[1010][10000];8 // dp[i][j] : i 個數&#xff0c;組成總和為j 的數量9 10 int main() 11 { 12 int n; 13 scanf("%d…

一張圖看懂云棲大會·上海峰會重磅產品發布

2018云棲大會上海峰會上&#xff0c;阿里云重磅發布一批產品并宣布了新一輪的價格調整&#xff0c;再次用科技普惠廣大開發者和用戶&#xff0c;詳情見長圖。 了解更多產品請戳&#xff1a;https://yunqi.aliyun.com/2018/shanghai/product?spm5176.8142029.759399.2.a7236d3e…

488. 祖瑪游戲

488. 祖瑪游戲 你正在參與祖瑪游戲的一個變種。 在這個祖瑪游戲變體中&#xff0c;桌面上有 一排 彩球&#xff0c;每個球的顏色可能是&#xff1a;紅色 ‘R’、黃色 ‘Y’、藍色 ‘B’、綠色 ‘G’ 或白色 ‘W’ 。你的手中也有一些彩球。 你的目標是 清空 桌面上所有的球。…

【黑客免殺攻防】讀書筆記14 - 面向對象逆向-虛函數、MFC逆向

虛函數存在是為了克服類型域解決方案的缺陷&#xff0c;以使程序員可以在基類里聲明一些能夠在各個派生類里重新定義的函數。 1 識別簡單的虛函數 代碼示例&#xff1a; #include "stdafx.h" #include <Windows.h>class CObj { public:CObj():m_Obj_1(0xAAAAAA…

怎么看另一個電腦端口是否通_誰一個人睡覺另一個看看夫妻的睡眠習慣

怎么看另一個電腦端口是否通In 2014, FiveThirtyEight took a survey of about 1057 respondents to get a look at the (literal) sleeping habits of the American public beyond media portrayal. Some interesting notices: first, that about 45% of all couples sleep to…

495. 提莫攻擊

495. 提莫攻擊 在《英雄聯盟》的世界中&#xff0c;有一個叫 “提莫” 的英雄。他的攻擊可以讓敵方英雄艾希&#xff08;編者注&#xff1a;寒冰射手&#xff09;進入中毒狀態。 當提莫攻擊艾希&#xff0c;艾希的中毒狀態正好持續 duration 秒。 正式地講&#xff0c;提莫在…

Java基礎之Collection和Map

List&#xff1a;實現了collection接口&#xff0c;list可以重復&#xff0c;有順序 實現方式&#xff1a;3種&#xff0c;分別為&#xff1a;ArrayList&#xff0c;LinkedList&#xff0c;Vector。 三者的比較&#xff1a; ArrayList底層是一個動態數組&#xff0c;數組是使用…

20155320《網絡對抗》Exp4 惡意代碼分析

20155320《網絡對抗》Exp4 惡意代碼分析 【系統運行監控】 使用schtasks指令監控系統運行 首先在C盤目錄下建立一個netstatlog.bat文件&#xff08;由于是系統盤&#xff0c;所以從別的盤建一個然后拷過去&#xff09;&#xff0c;用來將記錄的聯網結果格式化輸出到netstatlog.…

tableau 自定義省份_在Tableau中使用自定義圖像映射

tableau 自定義省份We have been reading about all the ways to make our vizzes in Tableau with more creativity and appeal. During my weekly practice for creating viz as part of makeovermonday2020 community, I came across geographical data which in way requir…

2055. 蠟燭之間的盤子

2055. 蠟燭之間的盤子 給你一個長桌子&#xff0c;桌子上盤子和蠟燭排成一列。給你一個下標從 0 開始的字符串 s &#xff0c;它只包含字符 ‘’ 和 ‘|’ &#xff0c;其中 ’ 表示一個 盤子 &#xff0c;’|’ 表示一支 蠟燭 。 同時給你一個下標從 0 開始的二維整數數組 q…