深入淺出 Java 虛擬機(三)OOM

本文章爲《深入淺出 Java 虛擬機》系列課程學習筆記,侵刪。學習地址爲 深入淺出 Java 虛擬機

1 JVM 中如何進行垃圾回收?

JVM 的 GC 動作並不受程序控制,它會在滿足條件的時候,自動觸發。

在發生 GC 的時候,一個對象,JVM 總能夠找到引用它的祖先。找到最後,如果發現這個祖先已經名存實亡了,它們都會被清理掉。而能夠躲過垃圾回收的那些祖先,比較特殊,它們的名字就叫作 GC Roots。

從 GC Roots 向下追溯、搜索,會產生一個叫作 Reference Chain 的鏈條。當一個對象不能和任何一個 GC Root 產生關係時,就會被清除。

2 什麼是 GC Roots?

GC Roots 是活躍的引用,可以理解爲程序通過引用可以訪問到的對象。一般分爲以下三類:

  1. 活動線程相關的各種引用,例如線程中與棧幀相關的各種引用(被調用的方法的引用類型參數、局部變量、臨時值)
  2. 類的靜態變量的引用
  3. JNI 引用

注意,我們這裏指的是活躍的引用,而不是對象,對象是不能作爲 GC Roots 的。

3 引用級別

  1. 強引用:即使程序會異常終止,這種對象也不會被回收。這種引用屬於最普通最強硬的一種存在,只有在和 GC Roots 斷絕關係時,纔會被消滅掉。例如 Object obj = new Object();
  2. 軟引用:軟引用用於維護一些可有可無的對象。在內存足夠的時候,軟引用對象不會被回收,只有在內存不足時,系統則會回收軟引用對象,如果回收了軟引用對象之後仍然沒有足夠的內存,纔會拋出內存溢出異常。軟引用適用於緩存技術上
  3. 弱引用:弱引用對象相比較軟引用,要更加無用一些,它擁有更短的生命週期。當 JVM 進行垃圾回收時,無論內存是否充足,都會回收被弱引用關聯的對象。它的應用場景和軟引用類似,可以在一些對內存更加敏感的系統裏採用
  4. 虛引用:如果一個對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收,主要用來跟蹤對象被垃圾回收的活動。虛引用必須與一個引用隊列關聯,當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象之前,把這個虛引用加入到與之關聯的引用隊列中。程序如果發現某個虛引用已經被加入到引用隊列,那麼就可以在所引用的對象的內存被回收之前採取必要的行動

4 OOM

OOM 即 Out Of Memory。當內存空間不足,系統撐不住了,JVM 就會拋出 OutOfMemoryError 錯誤。內存區域有哪些會發生 OOM 呢?

在這裏插入圖片描述
除了程序計數器,其他區域都有 OOM 溢出的可能。但是最常見的還是發生在堆上。

在這裏插入圖片描述
爲什麼會引起 OOM 呢?主要原因如下:

  1. 內存的容量太小了,需要擴容,或者需要調整堆的空間
  2. 錯誤的引用方式,發生了內存泄漏。沒有及時的切斷與 GC Roots 的關係。比如線程池裏的線程,在複用的情況下忘記清理 ThreadLocal 的內容
  3. 接口沒有進行範圍校驗,外部傳參超出範圍。比如數據庫查詢時的每頁條數等
  4. 對堆外內存無限制的使用。這種情況一旦發生更加嚴重,會造成操作系統內存耗盡

典型的內存泄漏場景,原因在於對象沒有及時的釋放自己的引用。比如一個局部變量,被外部的靜態集合引用。

拉勾教育版權所有:https://kaiwu.lagou.com/course/courseInfo.htm?courseId=31

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章