自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

JVM 垃圾回收的工作原理

開發(fā)
本文討論了各種不同的 JVM 內(nèi)存“代”,以及它們是如何在分代垃圾回收算法中起作用的。對于程序員來說,掌握 Java 的內(nèi)存管理機制并不是必須的,但它能夠幫助你更好地理解 JVM 處理程序中的變量和類實例的方式。

對于程序員來說,掌握 Java 的內(nèi)存管理機制并不是必須的,但它能夠幫助你更好地理解 JVM 是如何處理程序中的變量和類實例的。

Java 之所以能夠如此流行,自動 垃圾回收Garbage Collection(GC)功不可沒,它也是 Java 最重要的幾個特性之一。在這篇文章中,我將說明為什么垃圾回收如此重要。本文的主要內(nèi)容為:自動的分代垃圾回收、JVM 劃分內(nèi)存的依據(jù),以及 JVM 垃圾回收的工作原理。

Java 內(nèi)存分配

Java 程序的內(nèi)存空間被劃分為以下四個區(qū)域:

  • 堆區(qū)Heap:對象實例就是在這個區(qū)域分配的。不過,當我們聲明一個對象時,堆中不會發(fā)生任何內(nèi)存分配,只是在棧中創(chuàng)建了一個對象的引用而已。
  • 棧區(qū)Stack:方法、局部變量和類的實例變量就是在這個區(qū)域分配的。
  • 代碼區(qū)Code:這個區(qū)域存放了程序的字節(jié)碼。
  • 靜態(tài)區(qū)Static:這個區(qū)域存放了程序的靜態(tài)數(shù)據(jù)和靜態(tài)方法。

什么是自動垃圾回收?

自動垃圾回收是這樣一個過程:首先,堆中的所有對象會被分類為“被引用的”和“未被引用的”;接著,“未被引用的對象”就會被做上標記,以待之后刪除。其中,“被引用的對象”是指程序中的某一部分仍在使用的對象,“未被引用的對象”是指目前沒有正在被使用的對象。

許多編程語言,例如 C 和 C++,都需要程序員手動管理內(nèi)存的分配和釋放。在 Java 中,這一過程是通過垃圾回收機制來自動完成的(盡管你也可以在代碼中調(diào)用 system.gc(); 來手動觸發(fā)垃圾回收)。

垃圾回收的基本步驟如下:

1、標記已使用和未使用的對象

在這一步驟中,已使用和未使用的對象會被分別做上標記。這是一個及其耗時的過程,因為需要掃描內(nèi)存中的所有對象,才能夠確定它們是否正在被使用。

標記已使用和未使用的對象

標記已使用和未使用的對象

2、掃描/刪除對象

有兩種不同的掃描和刪除算法:

簡單刪除(標記清除):它的過程很簡單,我們只需要刪除未被引用的對象即可。但是,后續(xù)給新對象分配內(nèi)存就會變得很困難了,因為可用空間被分割成了一塊塊碎片。

標記清除的過程

標記清除的過程

刪除壓縮(標記整理):除了會刪除未被引用的對象,我們還會壓縮被引用的對象(未被刪除的對象)。這樣以來,新對象的內(nèi)存分配就相對容易了,并且內(nèi)存分配的效率也有了提升。

標記整理的過程

標記整理的過程

什么是分代垃圾回收,為什么需要它?

正如我們在“掃描刪除”模型中所看到的,一旦對象不斷增長,我們就很難掃描所有未使用的對象以回收內(nèi)存。不過,有一項實驗性研究指出,在程序執(zhí)行期間創(chuàng)建的大多數(shù)對象,它們的存活時間都很短。

既然大多數(shù)對象的存活時間都很短,那么我們就可以利用這個事實,從而提升垃圾回收的效率。該怎么做呢?首先,JVM 將內(nèi)存劃分為不同的“代”。接著,它將所有的對象都分類到這些內(nèi)存“代”中,然后對這些“代”分別執(zhí)行垃圾回收。這就是“分代垃圾回收”。

堆內(nèi)存的“代”和分代垃圾回收過程

為了提升垃圾回收中的“標記清除”的效率,JVM 將對內(nèi)存劃分成以下三個“代”:

  • 新生代Young Generation
  • 老年代Old Generation
  • 永久代Permanent Generation

Hotspot 堆內(nèi)存結(jié)構(gòu)

Hotspot 堆內(nèi)存結(jié)構(gòu)

下面我將介紹每個“代”及其主要特征。

新生代

所有創(chuàng)建不久的對象都存放在這里。新生代被進一步分為以下兩個區(qū)域:

  1. 伊甸區(qū)Eden:所有新創(chuàng)建的對象都在此處分配內(nèi)存。
  2. 幸存者區(qū)Survivor,分為 S0 和 S1:經(jīng)歷過一次垃圾回收后,仍然存活的對象會被移動到兩個幸存者區(qū)中的一個。

對象分配

對象分配

在新生代發(fā)生的分代垃圾回收被稱為 “次要回收Minor GC”(LCTT 譯注:也稱為“新生代回收Young GC”)。Minor GC 過程中的每個階段都是“停止世界Stop The World”(STW)的,這會導致其他應(yīng)用程序暫停運行,直到垃圾回收結(jié)束。這也是次要回收更快的原因。

一句話總結(jié):伊甸區(qū)存放了所有新創(chuàng)建的對象,當它的可用空間被耗盡,第一次垃圾回收就會被觸發(fā)。

填充伊甸區(qū)

填充伊甸區(qū)

次要回收:在該垃圾回收過程中,所有存活和死亡的對象都會被做上標記。其中,存活對象會被移動到 S0 幸存者區(qū)。當所有存活對象都被移動到了 S0,未被引用的對象就會被刪除。

拷貝被引用的對象

拷貝被引用的對象

S0 中的對象年齡為 1,因為它們挺過了一次次要回收。此時,伊甸區(qū)和 S1 都是空的。

每當完成清理后,伊甸區(qū)就會再次接受新的存活對象。隨著時間的推移,伊甸區(qū)和 S0 中的某些對象被宣判死亡(不再被引用),并且伊甸區(qū)的可用空間也再次耗盡(填滿了),那么次要回收 又將再次被觸發(fā)。

對象年齡增長

對象年齡增長

這一次,伊甸區(qū)和 S0 中的死亡和存活的對象會被做上標記。其中,伊甸區(qū)的存活對象會被移動到 S1,并且年齡增加至 1。S0 中的存活對象也會被移動到 S1,并且年齡增加至 2(因為它們挺過了兩次次要回收)。此時,伊甸區(qū)和 S0 又是空的了。每次次要回收之后,伊甸區(qū)和兩個幸存者區(qū)中的一個都會是空的。

新對象總是在伊甸區(qū)被創(chuàng)建,周而復(fù)始。當下一次垃圾回收發(fā)生時,伊甸區(qū)和 S1 都會被清理,它們中的存活對象會被移動到 S0 區(qū)。每次次要回收之后,這兩個幸存者區(qū)(S0 和 S1)就會交換一次。

額外年齡增長

額外年齡增長

這個過程會一直進行下去,直到某個存活對象的年齡達到了某個閾值,然后它就會被移動到一個叫做“老年代”的地方,這是通過一個叫做“晉升”的過程來完成的。

使用 -Xmn 選項可以設(shè)置新生代的大小。

老年代

這個區(qū)域存放著那些挺過了許多次次要回收,并且達到了某個年齡閾值的對象。

晉升

晉升

在上面這個示例圖表中,晉升的年齡閾值為 8。在老年代發(fā)生的垃圾回收被稱為 “主要回收Major GC”。(LCTT 譯注:也被稱為“全回收Full GC”)

使用 -Xms 和 -Xmx 選項可以分別設(shè)置堆內(nèi)存大小的初始值和最大值。(LCTT 譯注:結(jié)合上面的 -Xmn 選項,就可以間接設(shè)置老年代的大小了。)

永久代

永久代存放著一些元數(shù)據(jù),它們與應(yīng)用程序、Java 標準環(huán)境以及 JVM 自用的庫類及其方法相關(guān)。JVM 會在運行時,用到了什么類和方法,就會填充相應(yīng)的數(shù)據(jù)。當 JVM 發(fā)現(xiàn)有未使用的類,就會卸載或是回收它們,從而為正在使用的類騰出空間。

使用 -XX:PermGen 和 -XX:MaxPerGen 選項可以分別設(shè)置永久代大小的初始值和最大值。

元空間

Java 8 引入了元空間Metaspace,并用它替換了永久代。這么做的好處是自動調(diào)整大小,避免了 內(nèi)存不足OutOfMemory(OOM)錯誤。

總結(jié)

本文討論了各種不同的 JVM 內(nèi)存“代”,以及它們是如何在分代垃圾回收算法中起作用的。對于程序員來說,掌握 Java 的內(nèi)存管理機制并不是必須的,但它能夠幫助你更好地理解 JVM 處理程序中的變量和類實例的方式。這種理解使你能夠規(guī)劃和排除代碼故障,并理解特定平臺固有的潛在限制。

責任編輯:未麗燕 來源: Linux中國
相關(guān)推薦

2022-03-21 11:33:11

JVM垃圾回收器垃圾回收算法

2022-01-20 10:34:49

JVM垃圾回收算法

2017-08-04 10:53:30

回收算法JVM垃圾回收器

2009-12-30 10:14:29

JVM垃圾回收

2023-08-08 10:29:55

JVM優(yōu)化垃圾回收

2010-09-25 15:19:01

2021-11-05 15:23:20

JVM回收算法

2009-12-25 16:15:31

JVM垃圾回收算法

2010-09-25 15:33:19

JVM垃圾回收

2024-03-11 16:27:02

垃圾回收器JVM

2010-09-26 16:42:04

JVM內(nèi)存組成JVM垃圾回收

2010-09-27 09:01:26

JVM分代垃圾回收

2017-04-25 14:39:55

JVM內(nèi)存Java

2010-09-25 15:26:12

JVM垃圾回收

2010-09-16 15:10:24

JVM垃圾回收機制

2022-06-07 07:10:40

MinorGCMajorGCFullGC

2009-04-28 13:48:09

2011-12-05 12:51:58

JVMJava

2010-01-06 09:28:08

JVM分代垃圾回收

2012-01-09 17:06:16

JavaJVM
點贊
收藏

51CTO技術(shù)棧公眾號