1. 程式人生 > >JVM垃圾回收(上)

JVM垃圾回收(上)

Java 中的垃圾回收,常常是由 JVM 幫我們做好的。雖然這節省了大家很多的學習的成本,提高了專案的執行效率,但是當專案變得越來越複雜,使用者量越來越大時,還是需要我們懂得垃圾回收機制,這樣也能進行更深一步的優化。

辨別物件存亡

垃圾回收( Garbage Collection,以下簡稱 GC ),從字面上理解,就是將已經分配出去的,但卻不再使用的記憶體回收回來,以便能夠再次分配。

在 JVM 中,垃圾就是指的死亡物件所佔據的堆空間( GC 是發生在堆空間中),那麼我們如果辨別一個物件是否死亡呢?JVM 使用的是引用計數法可達性分析

引用計數法

引用計數法( Reference Counting),是為每個物件新增一個引用計數器,用來統計引用該物件的個數。一旦某個物件的引用計數器為0,則說明該物件已經死亡,便可以被回收了。

其具體實現為:

如果有一個引用,被賦值為某一物件,那麼將該物件的引用計數器 +1。

如果一個指向某一物件的引用,被賦值為其他值,那麼將該物件的引用計數器 -1。

也就是說,我們需要截獲所有的引用更新操作,並且相應地增減目標物件的引用計數器。

看似很簡單的實現,其實裡面有不少缺陷:

  1. 需要額外的空間來儲存計數器。
  2. 計數器的更新操作十分繁瑣。
  3. 最重要的:無法處理迴圈引用物件。

針對第3點,舉個例子特別說明一下:

假設物件 a 與 b 相互引用,除此之外沒有其他引用指向他們。在這種情況下,a 和 b 實際上已經死了。

但由於它們的引用計數器皆不為0(因為相互引用,兩者均為1),在引用計數法的計算中,這兩個物件還活著。因此,這些迴圈引用物件所佔據的空間將不可回收,從而造成了記憶體洩露

可達性分析

可達性分析( Reachability Analysis ),是目前 JVM 主要採取的判定物件死亡的方法。實質在於將一系列GC Roots作為初始的存活物件合集(live set),然後從該合集出發,探索所有能夠被該集合引用到的物件,並將其加入到該集合中,這個過程我們也稱之為標記(mark)。最終,未被探索到的物件便是死亡的,是可以回收的。

那麼什麼是GC Roots呢?我們可以暫時理解為由堆外指向堆內的引用,一般而言,GC Roots 包括(但不限於)如下幾種:

  1. Java 方法棧楨中的區域性變數
  2. 已載入類的靜態變數
  3. JNI handles
  4. 已啟動且未停止的 Java 執行緒

之前我們說引用計數法會有迴圈引用的問題,可達性分析就不會了。舉例來說,即便物件 a 和 b 相互引用,只要從 GC Roots 出發無法到達 a 或者 b,那麼可達性分析便會認為它們已經死亡。

可達性分析有沒有什麼缺點呢?有的,在多執行緒環境下,其他執行緒可能會更新已經分析過的物件中的引用,從而造成誤報(將引用設定為 null)或者漏報(將引用設定為未被訪問過的物件)。

誤報並沒有什麼傷害,JVM 至多損失了部分垃圾回收的機會。漏報則比較麻煩,因為垃圾回收器可能回收事實上仍被引用的物件記憶體。一旦從原引用訪問已經被回收了的物件,則很有可能會直接導致 JVM 崩潰。

STW

既然可達性分析在多執行緒下有缺點,那 JVM 是如何解決的呢?答案便是 Stop-the-world(以下簡稱JWT),停止了其他非垃圾回收執行緒的工作直到完成垃圾回收。這也就造成了垃圾回收所謂的暫停時間(GC pause)。

那 SWT 是如何實現的呢?當 JVM 收到 SWT 請求後,它會等待所有的執行緒都到達安全點(Safe Point),才允許請求 SWT 的執行緒進行獨佔的工作。

那什麼又叫安全點呢?安全點是 JVM 能找到一個穩定的執行狀態,在這個執行狀態下,JVM 的堆疊不會發生變化。

這麼一來,垃圾回收器便能夠“安全”地執行可達性分析,所有存活的物件也都可以成功被標記,那麼之後就可以將死亡的物件進行垃圾回收了。

總結

以上便是發現死亡物件的過程,這也為之後的垃圾回收進行鋪墊,具體的垃圾回收過程,我會在下一篇文章中講述,敬請期待。

有興趣的話可以訪問我的部落格或者關注我的公眾號、頭條號,說不定會有意外的驚喜。

https://death00.github.io/

相關推薦

JVM垃圾回收

Java 中的垃圾回收,常常是由 JVM 幫我們做好的。雖然這節省了大家很多的學習的成本,提高了專案的執行效率,但是當專案變得越來越複雜,使用者量越來越大時,還是需要我們懂得垃圾回收機制,這樣也能進行更深一步的優化。 辨別物件存亡 垃圾回收( Garbage Collection,以下簡稱 GC ),從字面

JVM——垃圾回收GC

.text 永久代 lines script from nes ng- code addclass GC簡單介紹 java語言執行在java虛擬機(jvm)上。為了解決有限的空間和性能的保證這個矛盾體,jvm所具備的GC能力。能夠有效的清除不用的對象。

深入拆解虛擬機器垃圾回收

引用計數法 (1)它的做法是為每個物件新增一個引用計數器,用來統計指向該物件的引用個數。一旦某個物件 的引用計數器為0,則說明該物件已經死亡,便可以被回收了。 (2)具體實現:如果有一個引用,被賦值為某一個物件,那麼該物件的引用計數器+1。如果指向某一個物件的引用,被賦值為其他值

JVM垃圾回收- GC算法:實現1

並行 ctime 配置 使用情況 ava 第一個 中標 算法 bsp GC算法:實現 上面我們介紹了GC算法中的核心概念,接下來我們看一下JVM裏的具體實現。首先必須了解的一個重要的事實是:對於大部分的JVM來說,兩種不同的GC算法是必須的,一個是清理Young Gene

JVM 垃圾回收GC機制

目錄 一、背景 二、 哪些記憶體需要回收? 1、引用計數演算法 2 、可達性分析演算法 三、 四種引用狀態 1、強引用 2、軟引用 3、弱引用 4、虛引用 物件死亡(被回收)前的最後一次掙扎 方法區如何判斷是否需要回收 四、垃圾收集

JVM垃圾回收演算法

1、回收演算法 標記回收演算法(Mark and Sweep GC) 從GC Roots集合開始,將記憶體整個遍歷一次,保留所有可以被GC Roots直接或間接引用到的物件,而剩下的物件都當作垃圾對待並回收,這個演算法需要中斷程序內其它元件的執行並

12 JVM 垃圾回收

-o 不用 通過 字節數 water 直接 重新 標記 被占用 Java 虛擬機的堆劃分 Java 虛擬機將堆劃分為新生代和老年代。其中新生代又被劃分為 Eden 區,以及兩個大小相同的 Survivor 區。 默認情況下,Java 虛擬機采取一種動態分配的策略,根據對象生

JVM垃圾回收

接著上一篇,介紹完了 JVM 中識別需要回收的垃圾物件之後,這一篇我們來說說 JVM 是如何進行垃圾回收。 首先要在這裡介紹一下80/20 法則: 約僅有20%的變因操縱著80%的局面。也就是說:所有變數中,最重要的僅有20%,雖然剩餘的80%佔了多數,控制的範圍卻遠低於“關鍵的少數”。 Java 物件

JVM垃圾回收GC

### JVM垃圾回收(GC) #### 1. 判斷物件是否可以被回收 - 引用計數法:每個物件有一個引用計數屬性,新增一個引用時計數加1,引用釋放時計數減1,計數為0時可以回收。此方法簡單,但**無法解決物件相互迴圈引用的問題**。 ```java // 迴圈引用 Node a=new N

JVM (四)--垃圾回收

程式計數器、虛擬機器棧、本地方法棧這三個區域屬於執行緒私有,只存在於執行緒的生命週期內,執行緒結束之後也會消失,因此,不需要對這三個區域進行垃圾回收。垃圾回收主要針對方法區和Java堆進行。 一、判斷一個物件是否存活 1、引用計數演算法 給物件新增一個引用計數器,當物件增加一個引用時

Java垃圾回收GC機制詳解

nbsp 引用計數 維護 png 對象 最新 新的 com 前沿 垃圾回收算法有兩種,根據不同的虛擬機策略不同 1、引用計數法 2、可達性分析法 由於我們平常使用的hotspot虛擬機用的是第二種。 那哪些是可達的呢? 這個算法的基本思想是通過一系列稱為“GC Roots”

各種垃圾回收

垃圾回收算法 告訴 策略 trac 銷毀 pin 完整 多線程 概念 1. 垃圾回收的意義  在C++中,對象所占的內存在程序結束運行之前一直被占用,在明確釋放之前不能分配給其它對象;而在Java中,當沒有對象引用指向原先分配給某個對象的內存時,該內存便成為垃圾。JVM的一

深入拆解虛擬機器垃圾回收

堆記憶體劃分 Java虛擬機器將堆分為新生代和老年代,並且對不同代採用不同的垃圾回收演算法。其中,新生代分為Eden區和兩個大小一致的Survivor區,並且其中一個Survivor區是空的 Minor GC (1)在只針對新生代的Minor GC中,Eden區和非S空

Java虛擬機器 :Java垃圾回收GC機制詳解

轉自:http://www.importnew.com/28413.html 哪些記憶體需要回收? 哪些記憶體需要回收是垃圾回收機制第一個要考慮的問題,所謂“要回收的垃圾”無非就是那些不可能再被任何途徑使用的物件。那麼如何找到這些物件? 1、引用計數法 這個演算法的實現是,給物件中新

Python3 垃圾回收GC

1. 小整數物件池 整數在程式中的使用非常廣泛,Python為了優化速度,使用了小整數物件池, 避免為整數頻繁申請和銷燬記憶體空間。 Python 對小整數的定義是 [-5, 257) 這些整數物件是提前建立好的,不會被垃圾回收。在一個 Python 的程式中,所有位於這個範圍內的整數使用

JAVA虛擬機器之一:垃圾回收GC機制

引言 java對於其它語言(c/c++)來說,建立一個物件使用後,不用顯式的delete/free,且能在一定程度上保證系統記憶體資源及時回收,這要功歸於java的自動垃圾回收機制(Garbage Collection,GC),但也是因為自動回收機制存在,一旦系統內洩漏或存

淺談java垃圾回收

本文簡述java垃圾回收機制自己的一點理解,希望能對java學習的朋友有一點幫助,謝謝; 先了解下JVM: JVM百度百科詳情https://baike.so.com/doc/1063579-1125177.html JVM是Java Virtual Machine(Java虛擬機器)的

對比Ruby和Python的垃圾回收2:代式垃圾回收機制

上週,我根據之前在RuPy上做的一個名為“Visualizing Garbage Collection in Ruby and Python.”的報告寫了這篇文章的上半部分。在上篇中,我解釋了標準Ruby(也被稱為Matz的Ruby直譯器或是MRI)是如何使用名為

Java中垃圾回收gc問題

以下哪項陳述是正確的? A. 垃圾回收執行緒的優先順序很高,以保證不再 使用的記憶體將被及時回收 B. 垃圾收集允許程式開發者明確指定釋放 哪一個物件 C. 垃圾回收機制保證了JAVA程式不會出現 記憶體溢位 D. 進入”Dead”狀態的執行緒將被垃圾回

Java垃圾回收物件存活狀態判斷---深入理解Java虛擬機器

程式計數器,虛擬機器棧和本地方法棧 首先我們先來看下垃圾回收中不會管理到的記憶體區域,在Java虛擬機器的執行時資料區我們可以看到,程式計數器,虛擬機器棧,本地方法棧這三個地方是比較特別的。這個三個部分的特點就是執行緒私有的,它們隨著執