天天看點

jvm學習——14.JVM垃圾回收概述JVM垃圾回收概述

135

JVM垃圾回收概述

什麼是垃圾?

  • ➢垃圾是指在運作程式中沒有任何指針指向的對象,這個對象就是需要被回收的垃圾。

    ➢外文: An object is considered garbage when it can no longer be reached from any pointer in the runningprogram.

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

  • 垃圾收集,不是Java語言的伴生産物。早在1960年,第一門開始使用記憶體動态配置設定和垃圾收集技術的Lisp語言誕生。
  • 垃圾收集機制是Java的招牌能力,極大地提高了開發效率。如今,垃圾收集幾乎成為現代語言的标配,即使經過如此長時間的發展,Java的垃圾收集機制仍然在不斷的演進中,不同大小的裝置、不同特征的應用場景,對垃圾收集提出了新的挑戰,這當然也是面試的熱點。
  • 關于垃圾回收的三個經典問題:
  1. 哪些垃圾需要回收?
  2. 什麼時候回收?
  3. 如何回收?

為什麼需要GC

  • 對于進階語言來說,一個基本認知是如果不進行垃圾回收,記憶體遲早都會被消耗完,因為不斷地配置設定記憶體空間而不進行回收,就好像不停地生産生活垃圾而從來不打掃一樣。
  • 除了釋放沒用的對象,垃圾回收也可以清除記憶體裡的記錄碎片。碎片整理将所占用的堆記憶體移到堆的一端,以便JVM 将整理出的記憶體配置設定給新的對象。
  • 随着應用程式所應付的業務越來越龐大、複雜,使用者越來越多,沒有GC就不能保證應用程式的正常進行。而經常造成STW(Stop-The-World)的GC又跟不上實際的需求,是以才會不斷地嘗試對GC進行優化。

136

早期垃圾回收

  • 在早期的C/C++時代,垃圾回收基本.上是手工進行的。開發人員可以使用 new關鍵字進行記憶體申請,并使用delete關鍵字進行記憶體釋放。比如以下代碼
MibBridge *pBridge = new cmBaseGroupBridge () ;
//如果注冊失敗,使用Delete釋放該對象所占記憶體區域
if (pBridge->Register(kDestroy)!= NO_ERROR)
delete pBridge;
           
  • 這種方式可以靈活控制記憶體釋放的時間,但是會給開發人員帶來頻繁申請和釋放記憶體的管理負擔。倘若有一處記憶體區間由于程式員編碼的問題忘記被回收,那麼就會産生記憶體洩漏(是指程式中己動态配置設定的堆記憶體由于某種原因,程式未釋放或無法釋放造成系統記憶體的浪費),垃圾對象永遠無法被清除,随着系統運作時間的不斷增長,垃圾對象所耗記憶體可能持續上升,直到出現記憶體溢出并造成應用程式崩潰。
  • 在有了垃圾回收機制後,上述代碼塊極有可能變成這樣:
MibBridge *pBridge = new cmBaseGroupBridge();
pBridge 一> Register(kDestroy);

           

記憶體洩漏:不用了但仍有引用指向,導緻無法回收

137

Java的垃圾回收機制

  • 自動記憶體管理,無需開發人員手動參與記憶體的配置設定與回收,這樣降低記憶體洩漏和記憶體溢出的風險
    • 沒有垃圾回收器,java也會和cpp一樣,各種懸垂指針,野指針,洩露問題讓你頭疼不已。
  • 自動記憶體管理機制,将程式員從繁重的記憶體管理中釋放出來,可以更專心地專注于業務開發
  • oracle官 網關于垃圾回收的介紹

    https://docs.oracle.com/javase/8/docs/ technotes/guides/vm/gctuning/toc.html

  • 對于Java開發人員而言,自動記憶體管理就像是一個黑匣子,如果過度依賴于 “自動”,那麼這将會是一場災難,最嚴重的就會弱化Java開發人員在程式出現記憶體溢出時定位問題和解決問題的能力。
  • 此時,了解JVM的自動記憶體配置設定和記憶體回收原理就顯得非常重要,隻有在真 正了解JVM是如何管理記憶體後,我們才能夠在遇見OutOfMemoryError時, 快速地根據錯誤異常日志定位問題和解決問題。
  • 當需要排查各種記憶體溢出、記憶體洩漏問題時,當垃圾收內建為系統達到更高并發量的瓶頸時,我們就必須對這些“自動化”的技術實施必要的監控和調節。
  • 垃圾回收器可以對年輕代回收,也可以對老年代回收,甚至是全堆和方法區的回收。

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

  • 從次數上講:

    頻繁收集Young區

    較少收集old區

    基本不動Perm區(方法區/元空間)

jvm學習——14.JVM垃圾回收概述JVM垃圾回收概述

大廠相關面試題

螞蟻金服:

  • 你知道哪幾種垃圾回收器,各自的優缺點,重點講一下 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回收停頓了幾次,為什麼要停頓兩次。

擴充:Java中throw 和 throws 的差別?

throw:

  • 表示方法内抛出某種異常對象
  • 如果異常對象是非 RuntimeException 則需要在方法申明時加上該異常的抛出 即需要加上 throws 語句 或者 在方法體内 try catch 處理該異常,否則編譯報錯
  • 執行到 throw 語句則後面的語句塊不再執行

throws:

  • 方法的定義上使用 throws 表示這個方法可能抛出某種異常
  • 需要由方法的調用者進行異常處理

代碼示例:

package constxiong.interview;
 
import java.io.IOException;
 
public class TestThrowsThrow {
 
	public static void main(String[] args) {
		testThrows();
		
		Integer i = null;
		testThrow(i);
		
		String filePath = null;
		try {
			testThrow(filePath);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 測試 throws 關鍵字
	 * @throws NullPointerException
	 */
	public static void testThrows() throws NullPointerException {
		Integer i = null;
		System.out.println(i + 1);
	}
	
	/**
	 * 測試 throw 關鍵字抛出 運作時異常
	 * @param i
	 */
	public static void testThrow(Integer i) {
		if (i == null) {
			throw new NullPointerException();//運作時異常不需要在方法上申明
		}
	}
	
	/**
	 * 測試 throw 關鍵字抛出 非運作時異常,需要方法體需要加 throws 異常抛出申明
	 * @param i
	 */
	public static void testThrow(String filePath) throws IOException {
		if (filePath == null) {
			throw new IOException();//運作時異常不需要在方法上申明
		}
	}
}
           

參考:https://blog.csdn.net/meism5/article/details/90414147