首頁 Java java教程 JVM的記憶體區域劃分以及垃圾回收機制詳解

JVM的記憶體區域劃分以及垃圾回收機制詳解

Jun 23, 2017 pm 03:11 PM
記憶體 區域 垃圾

在我們寫Java程式碼時,大部分情況下是不用關心你New的物件是否被釋放掉,或是何時被釋放掉。因為JVM中有垃圾自動回收機制。在之前的部落格中我們聊過Objective-C中的MRC(手動引用計數)以及ARC(自動引用計數)的記憶體管理方式,下方會對其進行回顧。而目前的JVM的記憶體回收機制則不是使用的引用計數,而是主要使用的「複製式回收」和「自適應回收」。

當然除了上面是這兩種演算法外,還有其他是演算法,下方也會介紹。這篇博客,我們先簡單聊聊JVM的區域劃分,然後在此基礎上介紹一下JVM的垃圾回收機制。

 

一、JVM記憶體區域分割簡述

##當然本部分簡單的聊一下JVM的記憶體區域的劃分,為下方垃圾回收機制內容的展開進行鋪墊。當然對JVM記憶體區域劃分的內容網上有很多詳細的內容,請自行Google。

根據JVM記憶體區域的劃分,簡單的畫了下方的這個示意圖。區域主要分為兩大塊,一塊是

堆區(Heap),我們所New出的物件都會在堆區進行分配,在C語言中的malloc所分配的方法就是從Heap區獲取的。而垃圾回收器主要是將堆區的記憶體回收的。

而另一部分則是

非堆區,非堆區主要包括用於編譯和保存本機程式碼的「程式碼快取區(Cache)」、保存JVM自己的靜態資料的「永生代(Perm Gen)」、存放方法參數局部變數等引用以及記錄方法呼叫順序的「Java虛擬機器堆疊(JVM Stack) 」和「本機方法堆疊(Local Method Stack)」。

  

垃圾回收器主要回收的是堆區中未使用的記憶體區域,並對對應的區域進行整理。在堆區中,又根據物件記憶體的存活時間或物件大小,分為「

年輕代」和「年老代」。 「年輕代」中的物件是不穩定的容易產生垃圾,而「年老代」中的物件比較穩定,不易產生垃圾。之所以將其分開,是分而治之,根據不同區域的記憶體區塊的特點,採取不同的記憶體回收演算法,從而提高堆區的垃圾回收的效率。下方會給予具體的介紹。

 

 

二、常見的記憶體回收演算法簡介

上面我們簡單的了解的

JVM中記憶體區域的劃分,接下來我們就來看看幾個常見的記憶體回收演算法。當然,下方所介紹的記憶體回收的演算法不僅是JVM中所使用到的,我們也會回顧OC中的記憶體回收方式。下方主要包括「引用計數式回收」、「複製式回收」、「標記整理式回收」、「分代式回收」。

 

1、引用計數式記憶體回收

引用計數(

Reference Count)式記憶體回收機制是Objective-C以及Swift語言中正在使用的記憶體回收機制,在先前的部落格中我們也詳細的聊過引用計數式的記憶體回收。只要有引用,那麼引用計數就加1。當引用計數為0時,該區塊記憶體就會被回收。當然這中記憶體清理方式容易形成「引用循環」。

Objective-C的參考計數中循環引用而造成記憶體外洩的問題,可以將變數宣告為weak或strong型別。也就是說我們可以將引用定義為「強引用」或「弱引用」。當出現「強引用循環」時,我們將其中的一個引用設為weak類型即可,然後這種強引用循環就被打破了,也就不會造成「記憶體外洩」的問題。關於「引用計數式記憶體回收」的更多以及更詳細的內容,請參考先前發布的關於OC內容的相關部落格。

為了更清晰的了解引用計數的工作方式,就簡單的畫了下方這個圖。在左邊的堆疊中的a、b、c三個引用分別指向堆中的不同區域塊。在堆中的記憶體區域區塊中,該區域有一個強引用時,其retainCount就會加1。而在弱引用時,就retainCount不會加1。

我們先來看看a引用的第1塊記憶體區域,因為該記憶體區塊只有a在強引用,所以retainCount=1,當a不在引用該記憶體區域時,retainCount=0,該記憶體會理解被回收的。這種情況下是不會造成記憶體外洩的。

我們再來看看b指向的記憶體區域2。 b和記憶體區塊3都強烈引用了記憶體區塊2,所以2的retainCount=2。而記憶體區塊2也強引用了記憶體區塊3,所以3的retainCount=1。所以b指向的這塊記憶體區域就存在“強引用循環”,因為當b不再指向這塊記憶體區域時,rc=2就會變成rc=1。因為retainCount不為零,所以這2塊記憶體區域是不會被釋放的,2不會被釋放,那麼自然而然的3塊內存區域也不會被釋放,但是這塊內存區域有不會再被使用到了,所以就會造成「記憶體外洩」的情況。如果這兩塊記憶體區域特別大,那麼我們可想而知,後果是比較嚴重的。

像c引用的這塊情況,就不會引起“強引用循環”,因為其中的一個引用鍊是弱引用的。當c不在引用第4塊記憶體時,rc由1變為零,那麼該區塊區域就會立即釋放。而記憶體區塊4被釋放後,記憶體區塊5的rc由1變成0,記憶體區塊5也會被釋放掉。這種情況下是不會造成記憶體外洩的。而在Objective-C中正是採用的這種方式來回收記憶體的,當然了,在OC中除了「強引用」和「弱引用」外,還有自動釋放池。也就是說,Autorealease類型的引用,讓retainCount = 0時,不會被立即釋放掉,而是在出自動釋放池時才會被釋放掉,在此就不做過多贅述了。

  

 

#2、複製式記憶體回收

聊完引用計數回收,我們知道引用計數容易引起“循環引用”的問題,為了解決“循環引用”引起的內存洩漏問題,OC中引入和“強引用”和“弱引用”的概念。接下來我們在看看複製式記憶體回收機制,在該機制中是不需要關心「循環引用」的問題的。簡單的說,複製式回收其核心就是“複製”,但前提是有條件複製。在垃圾回收時,將「活對象」複製到另一塊空白的堆區,然後將先前的區域一併清除。 「活物件」就是指沿著物件的引用鏈可以到「棧」上的物件。當然將活體物件複製到新的「堆區」後,也要將棧區的參考進行修改。

下方就是我們畫的複製式回收的簡圖,主要將堆分為兩大部分,在進行垃圾回收時,會將一個堆上的活對象複製到另一個堆上。下方堆1區是目前正在使用的區塊,堆2區則是空閒區。而在堆1區中未被標記的那些記憶體區塊,也就是2、3是要被回收的垃圾物件。而1、4、5是要被複製的「活對象」。因為沿著堆疊上的a可到達區塊1、沿著c可到達區塊4、5。而區塊2和3雖然有引用,但是不是來自非堆區,也就是2和3的引用都是來自堆區的引用,所以是要被回收的物件。

  

找到了活物件後,接下來要做的就是將活物件複製,將其複製到堆2區。當然,複製到堆2區的物件間的記憶體位址是連續的,如果要分配新的記憶體空間的話,直接從堆空閒的一段分配即可。這樣在分配記憶體空間時的效率是比較高的。物件複製後,要修改來自「非堆區」的引用位址。如下圖所示。

  

複製完畢後,我們直接將堆2區的中的所有記憶體空間回收即可,下方就是複製回收後的最終結果。下方的堆1區清空後,可以接收複製過來的物件了。當堆2區進行垃圾回收時,會把堆2區的活物複製到堆1區上。

從這個實例中我們可以看出當記憶體垃圾特別多的時候「複製式」垃圾回收的效率還是比較高的,因為複製的物件比較少,清除時直接將舊的堆空間進行清理即可。但是,當垃圾比較少的時候,這種方式會複製大量的活對象,效率還是比較低的。這種方式也會將堆的儲存空間進行分半。也就是說,總有一半是空閒的,堆空間的利用率不高。

  

 

#3、標記-壓縮回收演算法

從上述##在「複製式」垃圾回收過程中,我們知道,垃圾多時其效率比較高,而垃圾少時,其工作方式效率是比較低的。那麼,接下來,我們來介紹另一種標記-壓縮回收演算法,這種演算法在垃圾少時的工作效率比較高,而垃圾多的情況下,工作效率反而不高,這就與「複製式」形成了互補。下方我們將對標記-壓縮回收演算法進行介紹。

標記-壓縮的第一部就是標記,需要將堆區中的「

活物件」進行標記。上面的內容我們已經聊了什麼是“活對象”,在此就不做過多贅述了。由「活對象」的特徵我們可以看出,下方的活對像是記憶體區域1和3,所以我們將其進行標記。

  

標記完成後,我們就開始進行壓縮了,將活物件壓縮到「堆疊區」的一段,然後將剩餘的部分進行清除。下方就是將1和3這兩個活對象進行了壓縮。壓縮後,將下方的空間進行Clean。也就是說Clean的部分,就可以分配新的物件了。

  

下方截圖是標記-壓縮清理後的狀態。標記-壓縮式垃圾回收可充分利用堆區的空間,當垃圾比較少時,這種處理方式效率還是比較高的,如果垃圾太多碎片化嚴重時,移動的“活對象”較多,效率比較低。這種方式可以與「複製式」結合使用,根據目前堆區的垃圾狀態來選擇哪種回收方式。剛好與

「複製式」形成優勢互補。將「複製式」、「標記-壓縮式」的回收方式進行整合的演算法,就是「分代式」垃圾回收機制,下方會詳細介紹。

  

 

#4、分代垃圾回收

#「分代」即根據物件易產生垃圾的狀態或物件的大小將其分為不同的代,可分為「年輕代」、「年老代」和「永久代」。 「永久代」不在堆中,再次先不做討論。根據分代垃圾回收的特點,畫了下方的簡圖。

在堆中,主要把區域分為「年輕代」、「年老代」。位於“年輕代”的物件記憶體創建的時間不長,更新比較快,易產生“內存垃圾”,所以“年輕代”的垃圾回收使用“複製式”回收方式效率比較高。 「年輕代」又可分為兩個區,一個是

Eden Space(伊甸園)和Survivor Sprace(倖存者區)。 Eden Space去主要存放那些初次被創建的對象,而Survivor Sprace存放的是從Eden Space倖存下來的「活對象」。在Survivor Sprace(倖存者區)中又分為form和to兩塊,用於相互複製物件來進行垃圾清理。

而“年老代”中存放的是一些“大對象”以及從

Survivor Sprace中存活下來的“對象”,一般到“年老代”的對像比較穩定,產生垃圾較少,針對這種情況,使用「標記-壓縮」式回收效率比較高。 「分代垃圾回收」主要是分而治之,根據不同對象的特性將其分類,根據分類的特點來具體選擇合適的垃圾回收方案。

  

 

#三、分代式垃圾回收的具體運作原理##

當然在JVM具體的垃圾回收時,根據線程分可分為使用單個線程回收的“串行垃圾回收”,使用多個線程回收的“並行垃圾回收」。依程式的掛起狀態,又可分為「獨佔式回收」與「並發式回收」。當然之前也多次聊過「並行」與「並發」絕對不是一個概念,切不可將其混淆。這篇部落格就不對上述這些方式進行詳述了,有興趣的,請自行Google。

下面我們來看看「分代式垃圾回收」的具體工作原理的完整步驟,來直觀的感受一下「分代式」的垃圾回收的執行方式。

 

1、垃圾回收前

#下圖是等待「分代垃圾回收 」的簡圖,從下圖中,我們可以看出在堆中有些已分配的物件記憶體並沒有被堆疊上引用,這些就是要被回收的物件。我們可以看出,下方的堆,整體上分為“年輕代”和“年老代”,而年輕代,有可細分為Eden Space, From以及To三個區域。關於每個區域的作用,在上面介紹「分代垃圾回收」時,我們已經介紹過了,所以在此部分我們不做詳細介紹了。

  

 

#2、分代垃圾回收

下圖是上述堆控件的垃圾回收過程。因為我們有上圖可以看出,To區域是空白區,可以接受被複製的物件。由於「年輕代」易產生記憶體垃圾,所以採用「複製式」記憶體回收的方式。我們將Eden Space和From兩個堆疊區塊中的「活物件」拷貝到To區。拷貝的同時,我們也要修改被拷貝記憶體的堆疊引用位址。而對From或Eden區域的「大物件」儲存空間則直接複製到「年老代」。因為「大物件」在From與To區多次複製的效率比較低,直接將其加入「年老代」以提高回收效率。

對於「年老代」的垃圾回收,就採用「標記-壓縮」式垃圾回收。首先,先將活對象進行「標記」。

  

 

#3、垃圾回收後的結果

下方就是「分代”垃圾回收後的具體結果。從下方簡圖中,我們可以看出,Eden Space和From中的活對像都被複製到了To區,而「年老代」的堆區的儲存空間也變化不少。而且在「年老代」中多出了從From區複製過來的大物件。具體如下圖所示。

  

 

 

四、Eclipse的GC日誌設定與分析

#上面聊這麼多,接下來我們來直觀的感受一下在Eclipse如何查看垃圾回收的過程以及分析垃圾回收的日誌資訊。預設情況下,是不顯示垃圾回收的過程以及列印日誌的,需要在運行配置中添加相關的配置項來列印垃圾回收的日誌。本部分我們來看看Eclipse中的垃圾回收日誌記錄的配置,然後我們來分析一下這些日誌記錄。當然我們這篇部落格中使用的是Java8,如果你用其他版本的Java列印出來的日誌資訊會略有不同,好開始本部分的內容。

1、設定Eclipse的運行設定

#在Eclipse中的運作設定中加入對應的配置項,垃圾回收時才會列印相應的日誌資訊。選擇我們的工程,然後找到

Run Configurations…

選項,進行運行時的設定。 ######  ######### ###

下方就是上述選項開啟的對話框,然後找到(x)=Arguments這個標籤欄,在VM arguments中加入對應的虛擬機器參數,這些參數都會作為工程在運作時的參數。下面我們新增了-XX:+PrintGCTimeStamps-XX:+PrintGCDetails兩個參數。由這兩個參數名稱我們不難看出對應參數所對應的功能,一個是列印垃圾回收時的時間戳,另一個是列印垃圾回收時的細節。當然還有好多其他的參數,例如選擇“垃圾回收”時的具體演算法的參數,以及選擇是“串行”還是“並行”的參數,還有一些選擇是“獨佔式”還是“並發式”垃圾回收的參數。在此就不做過多贅述了,請自行Google。

  

 

#2、回收日誌的列印與解析

##已配置完上述參數後,當我們使用

System.gc(); 來進行強制垃圾回收時,會列印出對應的參數資訊。首先我們得創建測試用的程式碼,下方就是我們所創建的測試類,當然測試類中的程式碼比較簡單。主要是new了以字串,然後將引用置為null, 最後呼叫System.gc()進行回收。具體程式碼如下所示:

package com.zeluli.gclog;public class GCLogTest {public static void main(String[] args) {
        String s = new String("Value");
        s = null;
        System.gc();
    }
}
登入後複製
 

下方就是上述程式碼所執行的效果,接下來我們將介紹下方日誌資訊的主要內容。

  • [PSYoungGen: 1997K->416K(38400K)] 1997K->424K(125952K), 0.0010277 secs]

    • PSYoungGen表示,並行對「年輕代」進行回收,1997K->416K表示年輕代相應區域中「回收前->回收後」的大小,而(38400K)表示「年輕代」堆的總大小。而後方的1997K->424K(125952K)資料是以整個堆的角度來看待的問題。 1997K(堆回收前使用的記憶體) -> 424K(堆回收後使用的記憶體)(125952K-堆的總記憶體空間)。

  • [ParOldGen: 8K->328K(87552K)]

    • ParOldGen並行回收“年老代”,後邊的參數與上述並行回收年輕代的參數類似,就不多說了。

  • [Metaspace: 2669K->2669K(1056768K)​​]

    • #則表示「元資料區」的回收情況,Metaspace及「永久代」區,用於存放靜態資料或系統方法的區域。

  

 

上述就是簡單的垃圾回收的日誌,這篇部落格的內容就先到這裡吧,關於JVM中的垃圾回收的內容還有很多,以後結合著具體情況,再陸陸續續的進行介紹。今天博客就先到這裡。

 

以上是JVM的記憶體區域劃分以及垃圾回收機制詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1318
25
PHP教程
1269
29
C# 教程
1248
24
印表機記憶體不足,無法列印頁面Excel或PowerPoint錯誤 印表機記憶體不足,無法列印頁面Excel或PowerPoint錯誤 Feb 19, 2024 pm 05:45 PM

如果在列印Excel工作表或PowerPoint簡報時遇到印表機記憶體不足的問題,這篇文章可能對您有所幫助。您可能收到類似的錯誤訊息,指出印表機記憶體不足,無法列印頁面。不過,您可以遵循一些建議來解決這個問題。為什麼列印時印表機記憶體不可用?印表機記憶體不足可能導致記憶體不可用錯誤。有時是由於印表機驅動程式設定過低,也可能是其他原因。大檔案大小印表機驅動程式過時或損壞已安裝的加載項的中斷印表機設定設定錯誤發生此問題也可能是因為MicrosoftWindows印表機驅動程式上的記憶體設定較低。修復列印

大內存優化,電腦升級16g/32g內存速度沒什麼變化怎麼辦? 大內存優化,電腦升級16g/32g內存速度沒什麼變化怎麼辦? Jun 18, 2024 pm 06:51 PM

對於機械硬碟、或SATA固態硬碟,軟體運轉速度的提升會有感覺,如果是NVME硬碟,可能感覺不到。一,註冊表導入桌面新建一個文字文檔,複製貼上如下內容,另存為1.reg,然後右鍵合併,並重新啟動電腦。 WindowsRegistryEditorVersion5.00[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager\MemoryManagement]"DisablePagingExecutive"=d

Windows輸入遇到掛起或記憶體使用率高的問題[修復] Windows輸入遇到掛起或記憶體使用率高的問題[修復] Feb 19, 2024 pm 10:48 PM

Windows的輸入體驗是關鍵的系統服務,負責處理來自各種人機介面設備的使用者輸入。它在系統啟動時自動啟動,在背景運行。然而,有時候這個服務可能會出現自動掛起或佔用過多記憶體的情況,導致系統效能下降。因此,及時監控和管理這個進程是至關重要的,以確保系統的效率和穩定性。在這篇文章中,我們將分享如何解決Windows輸入體驗被掛起或導致記憶體使用率高的問題。 Windows輸入體驗服務沒有使用者介面,但它與處理與輸入裝置相關的基本系統任務和功能有密切關聯。它的作用是幫助Windows系統理解使用者輸入的每一

小米14Pro如何查看記憶體佔用? 小米14Pro如何查看記憶體佔用? Mar 18, 2024 pm 02:19 PM

最近,小米發布了一款功能強大的高階智慧型手機小米14Pro,它不僅外觀設計時尚,而且擁有內在和外在的黑科技。這款手機擁有頂級的性能和出色的多工處理能力,讓用戶能夠享受快速且流暢的手機使用體驗。但效能也是會收到記憶體的影響的,很多用戶想要知道小米14Pro如何查看記憶體佔用,趕快來看看吧。小米14Pro如何查看記憶體佔用?小米14Pro查看記憶體佔用方法介紹開啟小米14Pro手機【設定】中的【應用程式管理】按鈕。查看已安裝的所有應用程式列表,瀏覽列表並找到你想查看的應用,點擊它進入應用程式詳細頁面。在應用程式詳細頁面中

電腦8g和16g記憶體差別大嗎? (電腦記憶體選8g還是16g) 電腦8g和16g記憶體差別大嗎? (電腦記憶體選8g還是16g) Mar 13, 2024 pm 06:10 PM

  新手用戶在購買電腦時,會好奇電腦記憶體8g和16g有什麼差別?應該選擇8g還是16g呢?針對這個問題,今天小編就來跟大家詳細說明一下。  電腦記憶體8g和16g的差別大嗎?  1、在一般家庭或是普通工作使用,8G運行記憶體可以滿足,因此在使用過程中8g和16g區別不大。  2、遊戲愛好者使用時候,目前大型遊戲基本上是6g起步,8g是最低標準。目前在螢幕是2k的情況下,更高解析度並不會帶來更高的幀數表現,因此對8g和16g也無較大差異。  3、對於音訊、視訊剪輯使用者來說,8g和16g會出現明顯區

消息稱三星電子、SK 海力士堆疊式行動記憶體 2026 年後商業化 消息稱三星電子、SK 海力士堆疊式行動記憶體 2026 年後商業化 Sep 03, 2024 pm 02:15 PM

本站9月3日消息,韓媒etnews當地時間昨報道稱,三星電子和SK海力士的「類HBM式」堆疊結構行動記憶體產品將在2026年後實現商業化。消息人士表示這兩大韓國記憶體巨頭將堆疊式行動記憶體視為未來重要收入來源,並計劃將「類HBM記憶體」擴展到智慧型手機、平板電腦和筆記型電腦中,為端側AI提供動力。綜合本站先前報導,三星電子的此類產品叫做LPWideI/O內存,SK海力士則將這方面技術稱為VFO。兩家企業使用了大致相同的技術路線,即將扇出封裝和垂直通道結合在一起。三星電子的LPWideI/O內存位寬達512

三星宣布完成 16 層混合鍵結堆疊製程技術驗證,預計在 HBM4 記憶體大面積應用 三星宣布完成 16 層混合鍵結堆疊製程技術驗證,預計在 HBM4 記憶體大面積應用 Apr 07, 2024 pm 09:19 PM

報告稱,三星電子的高層DaeWooKim表示,在2024年韓國微電子和封裝學會年會上,三星電子將完成採用16層混合鍵結HBM記憶體技術的驗證。據悉,這項技術已通過技術驗證。報告也稱,此次技術驗證將為未來若干年內的記憶體市場發展奠定基礎。 DaeWooKim表示,三星電子成功製造了基於混合鍵合技術的16層堆疊HBM3內存,該內存樣品工作正常,未來16層堆疊混合鍵合技術將用於HBM4內存量產。 ▲圖源TheElec,下同相較現有鍵合工藝,混合鍵結無需在DRAM記憶體層間添加凸塊,而是將上下兩層直接銅對銅連接,

已安裝的記憶體未顯示在Windows 11上 已安裝的記憶體未顯示在Windows 11上 Mar 10, 2024 am 09:31 AM

如果您已經安裝了新的RAM,但它沒有顯示在您的Windows電腦上,本文將幫助您解決此問題。通常,我們會透過升級RAM來提高系統的效能。然而,系統效能也取決於其他硬件,如CPU、SSD等。升級RAM也可以提升您的遊戲體驗。有些使用者註意到安裝的內存在Windows11/10中沒有顯示。如果您遇到這種情況,您可以使用此處提供的建議。已安裝的記憶體未顯示在Windows11上如果您的Windows11/10PC上沒有顯示已安裝的RAM,以下建議將對您有所幫助。安裝的記憶體是否與您的電腦主機板相容?在BIO

See all articles