1. 程式人生 > 實用技巧 >【JVM之記憶體與垃圾回收篇】垃圾回收概述

【JVM之記憶體與垃圾回收篇】垃圾回收概述

垃圾回收概述

概念

這次我們主要關注的是黃色部分,記憶體的分配與回收

垃圾收集

垃圾收集,不是 Java 語言的伴生產物。早在 1960 年,第一門開始使用記憶體動態分配和垃圾收集技術的 Lisp 語言誕生。

關於垃圾收集有三個經典問題:

  • 哪些記憶體需要回收?
  • 什麼時候回收?
  • 如何回收?

垃圾收集機制是 Java 的招牌能力,極大地提高了開發效率。如今,垃圾收集幾乎成為現代語言的標配,即使經過如此長時間的發展,Java 的垃圾收集機制仍然在不斷的演進中,不同大小的裝置、不同特徵的應用場景,對垃圾收集提出了新的挑戰,這當然也是面試的熱點

什麼是垃圾?

在提到什麼是垃圾之前,我們先看下面一張圖


從上圖我們可以很明確的知道,Java 和 C++ 語言的區別,就在於垃圾收集技術和記憶體動態分配上,C 語言沒有垃圾收集技術,需要我們手動的收集。

什麼是垃圾(Garbage)呢?

  • 垃圾是指在執行程式中沒有任何指標指向的物件,這個物件就是需要被回收的垃圾。
  • 英文:An object is considered garbage when it can no longer be reached from any pointer in the running program.

如果不及時對記憶體中的垃圾進行清理,那麼,這些垃圾物件所佔的記憶體空間會一直保留到應用程式的結束,被保留的空間無法被其它物件使用,甚至可能導致記憶體溢位

磁碟碎片整理

機械硬碟需要進行磁碟整理,同時還有壞道

大廠面試題

螞蟻金服

  • 你知道哪幾種垃圾回收器,各自的優缺點,重點講一下 cms 和 G1?
  • JVM GC 演算法有哪些,目前的 JDK 版本採用什麼回收演算法?
  • G1 回收器講下回收過程 GC 是什麼?為什麼要有 GC?
  • GC 的兩種判定方法?CMS 收集器與 G1 收集器的特點

百度

  • 說一下 GC 演算法,分代回收說下
  • 垃圾收集策略和演算法

天貓

  • JVM GC 原理,JVM 怎麼回收記憶體
  • CMS 特點,垃圾回收演算法有哪些?各自的優缺點,他們共同的缺點是什麼?

滴滴
Java 的垃圾回收器都有哪些,說下 G1 的應用場景,平時你是如何搭配使用垃圾回收器的

京東

  • 你知道哪幾種垃圾收集器,各自的優缺點,重點講下 cms 和 G1,
  • 包括原理,流程,優缺點。垃圾回收演算法的實現原理

阿里

  • 講一講垃圾回收演算法。
  • 什麼情況下觸發垃圾回收?
  • 如何選擇合適的垃圾收集演算法?
  • JVM 有哪三種垃圾回收器?

位元組跳動

  • 常見的垃圾回收器演算法有哪些,各有什麼優劣?
  • System.gc()Runtime.gc() 會做什麼事情?
  • Java GC 機制?GC Roots 有哪些?
  • Java 物件的回收方式,回收演算法。
  • CMS 和 G1 瞭解麼,CMS 解決什麼問題,說一下回收的過程。
  • CMS 回收停頓了幾次,為什麼要停頓兩次?

為什麼需要GC

對於高階語言來說,一個基本認知是如果不進行垃圾回收,記憶體遲早都會被消耗完,因為不斷地分配記憶體空間而不進行回收,就好像不停地生產生活垃圾而從來不打掃一樣。

除了釋放沒用的物件,垃圾回收也可以清除記憶體裡的記錄碎片。碎片整理將所佔用的堆記憶體移到堆的一端,以便 JVM 將整理出的記憶體分配給新的物件

隨著應用程式所應付的業務越來越龐大、複雜,使用者越來越多,沒有 GC 就不能保證應用程式的正常進行。而經常造成 STW 的 GC 又跟不上實際的需求,所以才會不斷地嘗試對 GC 進行優化。

早期垃圾回收

在早期的 C/C++ 時代,垃圾回收基本上是手工進行的。開發人員可以使用 new 關鍵字進行記憶體申請,並使用 delete 關鍵字進行記憶體釋放。比如以下程式碼:

MibBridge *pBridge= new cmBaseGroupBridge();
//如果註冊失敗,使用Delete釋放該物件所佔記憶體區域
if(pBridge->Register(kDestroy)!=NO ERROR)
    delete pBridge;

這種方式可以靈活控制記憶體釋放的時間,但是會給開發人員帶來頻繁申請和釋放記憶體的管理負擔。倘若有一處記憶體區間由於程式設計師編碼的問題忘記被回收,那麼就會產生記憶體洩漏,垃圾物件永遠無法被清除,隨著系統執行時間的不斷增長,垃圾物件所耗記憶體可能持續上升,直到出現記憶體溢位並造成應用程式崩潰

有了垃圾回收機制後,上述程式碼極有可能變成這樣

MibBridge *pBridge=new cmBaseGroupBridge(); 
pBridge->Register(kDestroy);

現在,除了 Java 以外,C#、Python、Ruby等語言都使用了自動垃圾回收的思想,也是未來發展趨勢,可以說這種自動化的記憶體分配和來及回收方式已經成為了線代開發語言必備的標準。

Java垃圾回收機制

優點

自動記憶體管理,無需開發人員手動參與記憶體的分配與回收,這樣降低記憶體洩漏和記憶體溢位的風險

  • 沒有垃圾回收器,java 也會和 cpp 一樣,各種懸垂指標,野指標,洩露問題讓你頭疼不已。

自動記憶體管理機制,將程式設計師從繁重的記憶體管理中釋放出來,可以更專心地專注於業務開發

Oracle 官網關於垃圾回收的介紹

擔憂

對於 Java 開發人員而言,自動記憶體管理就像是一個黑匣子,如果過度依賴於“自動”,那麼這將會是一場災難,最嚴重的就會弱化 Java 開發人員在程式出現記憶體溢位時定位問題和解決問題的能力。

此時,瞭解 JVM 的自動記憶體分配和記憶體回收原理就顯得非常重要,只有在真正瞭解 JVM 是如何管理記憶體後,我們才能夠在遇見 OutOfMemoryError 時,快速地根據錯誤異常日誌定位問題和解決問題。

當需要排查各種記憶體溢位、記憶體洩漏問題時,當垃圾收整合為系統達到更高併發量的瓶頸時,我們就必須對這些“自動化”的技術實施必要的監控和調節。

GC主要關注的區域

GC 主要關注於方法區和堆中的垃圾收集

垃圾收集器可以對年輕代回收,也可以對老年代回收,甚至是全棧和方法區的回收

  • 其中,Java 堆是垃圾收集器的工作重點

從次數上講:

  • 頻繁收集 Young 區
  • 較少收集 Old 區
  • 基本不收集 Perm 區(元空間)