bl双性强迫侵犯h_国产在线观看人成激情视频_蜜芽188_被诱拐的少孩全彩啪啪漫画

詳解Java虛擬機(第⑤篇)——垃圾收集-創新互聯

詳解Java 虛擬機(第⑤篇)——垃圾收集

垃圾收集主要是針對堆和方法區進行。程序計數器、虛擬機棧和本地方法棧這三個區域屬于線程私有的,只存在于線程的生命周期內,線程結束之后就會消失,因此不需要對這三個區域進行垃圾回收。

成都創新互聯公司成都網站建設按需制作,是成都網站營銷公司,為不銹鋼雕塑提供網站建設服務,有成熟的網站定制合作流程,提供網站定制設計服務:原型圖制作、網站創意設計、前端HTML5制作、后臺程序開發等。成都網站維護熱線:028-86922220

一、判斷一個對象是否可被回收

1. 引用計數算法

為對象添加一個引用計數器,當對象增加一個引用時計數器加 1,引用失效時計數器減 1。引用計數為 0 的對象可被回收。

在兩個對象出現循環引用的情況下,此時引用計數器永遠不為 0,導致無法對它們進行回收。正是因為循環引用的存在,因此 Java 虛擬機不使用引用計數算法。

public class Test {
    public Object instance = null;
    public static void main(String[] args) {
        Test a = new Test();
        Test b = new Test();
        a.instance = b;
        b.instance = a;
        a = null;
        b = null;
        doSomething();
    }
}

在上述代碼中,a 與 b 引用的對象實例互相持有了對象的引用,因此當我們把對 a 對象與 b 對象的引用去除之后,由于兩個對象還存在互相之間的引用,導致兩個 Test 對象無法被回收。

  • 優點:執行效率高,程序執行受影響較小。
  • 缺點:無法檢測出循環引用的情況,引起內存泄漏。

2. 可達性分析算法

通過判斷對象的引用鏈是否可達來決定對象是否可以被回收。

以 GC Roots 為起始點進行搜索,可達的對象都是存活的,不可達的對象可被回收。

Java 虛擬機使用該算法來判斷對象是否可被回收,GC Roots 一般包含以下內容:

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

3. 方法區的回收

因為方法區主要存放永久代對象,而永久代對象的回收率比新生代低很多,所以在方法區上進行回收性價比不高。

主要是對常量池的回收和對類的卸載。

為了避免內存溢出,在大量使用反射和動態代理的場景都需要虛擬機具備類卸載功能。

類的卸載條件很多,需要滿足以下三個條件,并且滿足了條件也不一定會被卸載:

  • 該類所有的實例都已經被回收,此時堆中不存在該類的任何實例。
  • 加載該類的 ClassLoader 已經被回收。
  • 該類對應的 Class 對象沒有在任何地方被引用,也就無法在任何地方通過反射訪問該類方法。

4. finalize()

類似 C++ 的析構函數,用于關閉外部資源。但是 try-finally 等方式可以做得更好,并且該方法運行代價很高,不確定性大,無法保證各個對象的調用順序,因此最好不要使用。

當一個對象可被回收時,如果需要執行該對象的 finalize() 方法,那么就有可能在該方法中讓對象重新被引用,從而實現自救。自救只能進行一次,如果回收的對象之前調用了 finalize() 方法自救,后面回收時不會再調用該方法。

Object 的finalize()方法的作用是否與C++的析構函數作用相同?

  • 與C++的析構函數不同,析構函數調用確定,而finalize()方法是不確定的;
  • 當垃圾回收器要宣告一個對象死亡時,至少要經歷兩次標記過程。如果對象在進行可達性分析以后,沒有與GC Root直接相連接的引用量,就會被第一次標記,并且判斷是否執行finalize()方法;如果這個對象覆蓋了finalize()方法,并且未被引用,就會被放置于F-Queue隊列,稍后由虛擬機創建的一個低優先級的finalize()線程去執行觸發finalize()方法;
  • 由于線程的優先級比較低,執行過程隨時可能會被終止;
  • 給予對象最后一次重生的機會

二、引用類型

無論是通過引用計數算法判斷對象的引用數量,還是通過可達性分析算法判斷對象是否可達,判定對象是否可被回收都與引用有關。

Java 提供了四種強度不同的引用類型。

1. 強引用

被強引用關聯的對象不會被回收。

使用 new 一個新對象的方式來創建強引用。

Object obj = new Object();

拋出OOM Error終止程序也不會回收具有強引用的對象,只有通過將對象設置為null來弱化引用,才能使其被回收。

2. 軟引用

表示對象處在有用但非必須的狀態。

被軟引用關聯的對象只有在內存不夠的情況下才會被回收。可以用來實現內存敏感的高速緩存。

使用 SoftReference 類來創建軟引用。

Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
obj = null;  // 使對象只被軟引用關聯

3. 弱引用

表示非必須的對象,比軟引用更弱一些。適用于偶爾被使用且不影響垃圾收集的對象。

被弱引用關聯的對象一定會被回收,也就是說它只能存活到下一次垃圾回收發生之前。

使用 WeakReference 類來創建弱引用。

Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
obj = null;

4. 虛引用

又稱為幽靈引用或者幻影引用,一個對象是否有虛引用的存在,不會對其生存時間造成影響,也無法通過虛引用得到一個對象。

不會決定對象的生命周期,任何時候都可能被垃圾回收器回收。必須和引用隊列ReferenceQueue聯合使用。

為一個對象設置虛引用的唯一目的是能在這個對象被回收時收到一個系統通知,起哨兵作用。具體來說,就是通過判斷引用隊列ReferenceQueue是否加入虛引用來判斷被引用對象是否被GC回收。

使用 PhantomReference 來創建虛引用。

Object obj = new Object();
ReferenceQueue queue = new ReferenceQueue();
PhantomReference<Object> pf = new PhantomReference<Object>(obj, queue);
obj = null;

引用隊列(ReferenceQueue):當GC(垃圾回收線程)準備回收一個對象時,如果發現它還僅有軟引用(或弱引用,或虛引用)指向它,就會在回收該對象之前,把這個軟引用(或弱引用,或虛引用)加入到與之關聯的引用隊列(ReferenceQueue)中。如果一個軟引用(或弱引用,或虛引用)對象本身在引用隊列中,就說明該引用對象所指向的對象被回收了。無實際的存儲結構,存儲邏輯依賴于內部節點之間的關系來表達。

三、垃圾收集算法

1. 標記 - 清除

在標記階段,從根集合進行掃描,會檢查每個對象是否為活動對象,如果是活動對象,則程序會在對象頭部打上標記。

在清除階段,會進行對象回收并取消標志位,另外,還會判斷回收后的分塊與前一個空閑分塊是否連續,若連續,會合并這兩個分塊。回收對象就是把對象作為分塊,連接到被稱為 “空閑鏈表” 的單向鏈表,之后進行分配時只需要遍歷這個空閑鏈表,就可以找到分塊。

在分配時,程序會搜索空閑鏈表尋找空間大于等于新對象大小 size 的塊 block。如果它找到的塊等于 size,會直接返回這個分塊;如果找到的塊大于 size,會將塊分割成大小為 size 與 (block - size) 的兩部分,返回大小為 size 的分塊,并把大小為 (block - size) 的塊返回給空閑鏈表。

不足:

  • 標記和清除過程效率都不高;
  • 會產生大量不連續的內存碎片,導致無法給大對象分配內存。

2. 標記 - 整理

讓所有存活的對象都向一端移動,然后直接清理掉端邊界以外的內存。

優點:

  • 不會產生內存碎片

不足:

  • 需要移動大量對象,處理效率比較低。

3. 復制

將內存劃分為大小相等的兩塊,每次只使用其中一塊,當這一塊內存用完了就將還存活的對象復制到另一塊上面,然后再把使用過的內存空間進行一次清理。

主要不足是只使用了內存的一半。

現在的商業虛擬機都采用這種收集算法回收新生代,但是并不是劃分為大小相等的兩塊,而是一塊較大的 Eden 空間和兩塊較小的 Survivor 空間,每次使用 Eden 和其中一塊 Survivor。在回收時,將 Eden 和 Survivor 中還存活著的對象全部復制到另一塊 Survivor 上,最后清理 Eden 和使用過的那一塊 Survivor。

HotSpot 虛擬機的 Eden 和 Survivor 大小比例默認為 8:1,保證了內存的利用率達到 90%。如果每次回收有多于 10% 的對象存活,那么一塊 Survivor 就不夠用了,此時需要依賴于老年代進行空間分配擔保,也就是借用老年代的空間存儲放不下的對象。

4. 分代收集

Stop-the-World

  • JVM由于要執行GC而停止了應用程序的執行;
  • 任何一種GC算法中都會發生;
  • 多數GC優化通過減少Stop-the-world發生的時間來提升程序性能。

Safepoint

分析過程中對象引用關系不會發生變化的點;
產生Safepoint的地方:方法調用;循環跳轉;異常跳轉等
現在的商業虛擬機采用分代收集算法,它根據對象存活周期將內存劃分為幾塊,不同塊采用適當的收集算法。

一般將堆分為新生代和老年代。

  • 新生代使用:復制算法
  • 老年代使用:標記 - 清除 或者 標記 - 整理 算法

四、垃圾收集器

以上是 HotSpot 虛擬機中的 7 個垃圾收集器,連線表示垃圾收集器可以配合使用。

  • 單線程與多線程:單線程指的是垃圾收集器只使用一個線程,而多線程使用多個線程;
  • 串行與并行:串行指的是垃圾收集器與用戶程序交替執行,這意味著在執行垃圾收集的時候需要停頓用戶程序;并行指的是垃圾收集器和用戶程序同時執行。除了 CMS 和 G1 之外,其它垃圾收集器都是以串行的方式執行。

1. Serial 收集器(-XX:+UseSerialGC)

Serial 翻譯為串行,也就是說它以串行的方式執行。

它是單線程的收集器,只會使用一個線程進行垃圾收集工作。

它的優點是簡單高效,在單個 CPU 環境下,由于沒有線程交互的開銷,因此擁有最高的單線程收集效率。

它是 Client 場景下的默認新生代收集器,因為在該場景下內存一般來說不會很大。它收集一兩百兆垃圾的停頓時間可以控制在一百多毫秒以內,只要不是太頻繁,這點停頓時間是可以接受的。

2. ParNew 收集器(-XX:+UseParNewGC)

它是 Serial 收集器的多線程版本。

它是 Server 場景下默認的新生代收集器,除了性能原因外,主要是因為除了 Serial 收集器,只有它能與 CMS 收集器配合使用。

3. Parallel Scavenge 收集器(-XX:+UseParallelGC)

與 ParNew 一樣是多線程收集器。

其它收集器目標是盡可能縮短垃圾收集時用戶線程的停頓時間,而它的目標是達到一個可控制的吞吐量,因此它被稱為“吞吐量優先”收集器。這里的吞吐量指 CPU 用于運行用戶程序的時間占總時間的比值。

停頓時間越短就越適合需要與用戶交互的程序,良好的響應速度能提升用戶體驗。而高吞吐量則可以高效率地利用 CPU 時間,盡快完成程序的運算任務,適合在后臺運算而不需要太多交互的任務。

縮短停頓時間是以犧牲吞吐量和新生代空間來換取的:新生代空間變小,垃圾回收變得頻繁,導致吞吐量下降。

可以通過一個開關參數打開 GC 自適應的調節策略(GC Ergonomics),就不需要手工指定新生代的大小(-Xmn)、Eden 和 Survivor 區的比例、晉升老年代對象年齡等細節參數了。虛擬機會根據當前系統的運行情況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或者大的吞吐量。

4. Serial Old 收集器(-XX:+UseSerialOldGC)

是 Serial 收集器的老年代版本,也是給 Client 場景下的虛擬機使用。如果用在 Server 場景下,它有兩大用途:

  • 在 JDK 1.5 以及之前版本(Parallel Old 誕生以前)中與 Parallel Scavenge 收集器搭配使用。
  • 作為 CMS 收集器的后備預案,在并發收集發生 Concurrent Mode Failure 時使用。

5. Parallel Old 收集器(-XX:+UseParallelOldGC)

是 Parallel Scavenge 收集器的老年代版本。

在注重吞吐量以及 CPU 資源敏感的場合,都可以優先考慮 Parallel Scavenge 加 Parallel Old 收集器。

6. CMS 收集器(-XX:+UseConcMarkSweepGC)

CMS(Concurrent Mark Sweep),Mark Sweep 指的是標記 - 清除算法。

分為以下六個流程:

  • 初始標記:僅僅只是標記一下 GC Roots 能直接關聯到的對象,速度很快,需要停頓。
  • 并發標記:進行 GC Roots Tracing 的過程,它在整個回收過程中耗時最長,不需要停頓。
  • 并發預清理:查找執行并發標記階段從年輕代晉升到老年代的對象
  • 重新標記:為了修正并發標記期間因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄,需要停頓。
  • 并發清除:清理垃圾對象,不需要停頓。
  • 并發重置:重置CMS收集器的數據結構,等待下一次垃圾回收。
    在整個過程中耗時最長的并發標記和并發清除過程中,收集器線程都可以與用戶線程一起工作,不需要進行停頓。

具有以下缺點:

  • 吞吐量低:低停頓時間是以犧牲吞吐量為代價的,導致 CPU 利用率不夠高。
  • 無法處理浮動垃圾,可能出現 Concurrent Mode Failure。浮動垃圾是指并發清除階段由于用戶線程繼續運行而產生的垃圾,這部分垃圾只能到下一次 GC 時才能進行回收。由于浮動垃圾的存在,因此需要預留出一部分內存,意味著 CMS 收集不能像其它收集器那樣等待老年代快滿的時候再回收。如果預留的內存不夠存放浮動垃圾,就會出現 Concurrent Mode Failure,這時虛擬機將臨時啟用 Serial Old 來替代 CMS。
  • 標記 - 清除算法導致的空間碎片,往往出現老年代空間剩余,但無法找到足夠大連續空間來分配當前對象,不得不提前觸發一次 Full GC。

7. G1 收集器(-XX:+UseG1GC)

G1(Garbage-First),它是一款面向服務端應用的垃圾收集器,在多 CPU 和大內存的場景下有很好的性能。HotSpot 開發團隊賦予它的使命是未來可以替換掉 CMS 收集器。

堆被分為新生代和老年代,其它收集器進行收集的范圍都是整個新生代或者老年代,而 G1 可以直接對新生代和老年代一起回收。

G1 把堆劃分成多個大小相等的獨立區域(Region),新生代和老年代不再物理隔離。

通過引入 Region 的概念,從而將原來的一整塊內存空間劃分成多個的小空間,使得每個小空間可以單獨進行垃圾回收。這種劃分方法帶來了很大的靈活性,使得可預測的停頓時間模型成為可能。通過記錄每個 Region 垃圾回收時間以及回收所獲得的空間(這兩個值是通過過去回收的經驗獲得),并維護一個優先列表,每次根據允許的收集時間,優先回收價值大的 Region。

每個 Region 都有一個 Remembered Set,用來記錄該 Region 對象的引用對象所在的 Region。通過使用 Remembered Set,在做可達性分析的時候就可以避免全堆掃描。

如果不計算維護 Remembered Set 的操作,G1 收集器的運作大致可劃分為以下幾個步驟:

  • 初始標記
  • 并發標記
  • 最終標記:為了修正在并發標記期間因用戶程序繼續運作而導致標記產生變動的那一部分標記記錄,虛擬機將這段時間對象變化記錄在線程的 Remembered Set Logs 里面,最終標記階段需要把 Remembered Set Logs 的數據合并到 Remembered Set 中。這階段需要停頓線程,但是可并行執行。
  • 篩選回收:首先對各個 Region 中的回收價值和成本進行排序,根據用戶所期望的 GC 停頓時間來制定回收計劃。此階段其實也可以做到與用戶程序一起并發執行,但是因為只回收一部分 Region,時間是用戶可控制的,而且停頓用戶線程將大幅度提高收集效率。

具備如下特點:

  • 并行和并發
  • 分代收集
  • 空間整合:整體來看是基于“標記 - 整理”算法實現的收集器,從局部(兩個 Region 之間)上來看是基于“復制”算法實現的,這意味著運行期間不會產生內存空間碎片。
  • 可預測的停頓:能讓使用者明確指定在一個長度為 M 毫秒的時間片段內,消耗在 GC 上的時間不得超過 N 毫秒。

五、降低停頓時間

1. 使用 CMS 收集器
CMS 收集器進行垃圾回收,有 4 個步驟:

  • 初始標記
  • 并發標記
  • 重新標記
  • 并發清除

其中初始標記和重新標記需要 “stop the world”,但耗時時間最長的并發標記、并發清除過程中,GC 線程都可與用戶線程一起工作。整體上說,CMS 和用戶線程是并行的。

2. 增量算法

基本思路:若一次性將所有垃圾進行處理,會造成系統長時間的停頓,則就讓 GC 線程與用戶線程交替執行。每次 GC 線程只收集一小塊區域的內存空間,接著切換到用戶線程,重復幾次,直至 GC 完成。

問題:存在線程切換和上下文切換,造成系統吞吐量下降。

名稱欄目:詳解Java虛擬機(第⑤篇)——垃圾收集-創新互聯
新聞來源:http://vcdvsql.cn/article14/epdde.html

成都網站建設公司_創新互聯,為您提供微信小程序虛擬主機網站排名微信公眾號靜態網站自適應網站

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

外貿網站制作