System.gc()
-
在默認情況下,通過System.gc()或者Runtime.getRuntime().gc()的調用,會顯式觸發Full GC,同時對老年代和新生代進行回收,嘗試釋放被丟棄對象占用的內存
-
然而System.gc()調用附帶一個免責聲明,無法保證對垃圾收集器的調用。
-
jvm實現者可以通過System.gc()調用來決定jvm的GC行為。而一般情況下,垃圾回收是自動進行的,無須手動觸發,否則就太過于麻煩了。在一些特殊情況下,比如我們在編寫一個性能基準,我們可以在運行之前調用System.gc()
-
方法3沒有GC,方法4GC。因為變量雖然只在代碼塊里面起作用,但是在方法3的局部變量表里還存在著,而方法4局部變量表里,value覆蓋了buffer
內存溢出
內存泄露
STW—Stop the World
- 指的是GC事件發生過程中,會產生應用程序的卡頓。停頓產生時整個應用程序線程都會被暫停,沒有任何響應,有點像卡死的感覺,這個停頓稱為STW
- 可達性分析算法中枚舉根節點(GC Roots)會導致所有Java執行線程停頓。
- 分析工具必須在一個能確保一致性的快照中進行
- 一致性指整個分析期間整個執行系統看起來像被凍結在某個時間點上
- 如果出現分析過程中對象引用關系還在不斷變化,則分析結果的準確性無法保證
- 可達性分析算法中枚舉根節點(GC Roots)會導致所有Java執行線程停頓。
- 被STW中斷的應用程序線程會在完成GC之后恢復,頻繁中斷會讓用戶感覺像網速不快造成電影卡帶一樣,所以我們需要減少STW的發生
- STW和采用哪款GC無關,所有的GC都有這個事件【只要用可達性分析算法的GC】
- 哪怕是G1也不能完全避免stop-the-world情況發生,只能說垃圾回收器越來越優秀,回收效率越來越高,盡可能地縮短了暫停時間
- STW是JVM在后臺自動發起和自動完成的。在用戶不可見的情況下,把用戶造成的工作線程全部停掉
- 開發中不要用System.gc()會導致STW
垃圾回收的并發與并行
安全點和安全區域
- 程序執行時,并非能在所有的地方都能停下來GC,只有在特定的位置停頓下來開始GC,這些位置稱為安全點(Safepoint)
- Safe Point 的選擇很重要,不能太多,不能太少。太多會導致程序頻繁停頓,影響程序性能,太少會導致GC等待的時間太長
- 通常會選擇一些執行時間較長的指令作為 SafePoint,比如方法調用,循環跳轉和異常跳轉等
- 如何在GC開始時,保證所有線程都跑到最近的安全點停下來?
- 搶占式中斷(現在沒有虛擬機用了):先中斷所有線程,如果有線程不足安全點,恢復那些線程,讓他們跑到安全點
- 主動式中斷:設置一個中斷標志(表示要GC了,需要中斷了),線程到達安全點會輪詢這個標志,如果這個標志為真,線程就會自己中斷掛起,如果為假,線程就繼續執行
- 安全區域:在線程處于Sleep或Blocked等不執行的狀態時,無法響應jvm的中斷請求,無法走到安全點去中斷掛起。jvm也不會等待線程喚醒。這時就需要安全區域了。安全區域指的是在一段代碼片段中,對象的引用關系不會發生變化,在這個區域中的任何位置開始GC都是安全的。可以把安全區域看成被擴展了的安全點
- 實際執行時:
- 1.當線程運行到SafeRegion的代碼時,首先標識這個線程進入了SafeRegion,如果這段時間內發生GC,jvm會忽略標識為SafeRegion狀態的線程【應該講錯了,應該不會忽略】
- 2.當線程即將離開安全區域時,會檢測GC是否已經完成,如果完成了,則繼續執行。如果沒有完成,線程必須等待直到收到可以安全離開安全區域的信號為止
引用【強軟弱虛!】
- 強引用——不會被回收
- 使用場景:平時new對象時,使用的就是強引用,普通程序99%都是強引用
- 一個普通對象,如果沒有被引用,或者超出了引用的作用域,或者強引用顯式賦值為null,就可以當作垃圾收集了
- 可以直接訪問目標對象
- 是造成內存泄露的一個原因
- 軟引用——直到不回收直到報OOM才會回收(內存夠的時候,GC了也不回收)
- 使用場景:緩存
- 只被軟引用關聯著的對象,在系統將要發生OOM前,會把這些對象列進回收范圍之中進行第二次回收。如果回收之后內存還是不夠,就OOM
- 垃圾回收器在某個時刻決定回收軟可達的對象時,會清理軟引用,并可選地把引用放到一個引用隊列
- 獲取對象是:userSoftRef.get()
- 弱引用——只要GC就會被回收
- 使用場景:緩存,比如用WeakHashMap做緩存
- 雖然一GC就會被回收,但是GC線程優先級很低,所有不一定能很快地發現持有弱引用的對象,可以存活較長時間
- 軟引用弱引用都很適合保存那些可有可無的緩存數據。因為它可以在內存多的時候可以存活較長時間,加速系統,內存不夠的時候也可以被回收,不被占用
- 虛引用——有了像沒有一樣,唯一目的(不是作用)是用來通知對象被回收了
- 也稱為“幽靈引用”“幻影引用”,是所有引用中最弱的一個
- 對象有了虛引用也不會影響它的GC過程,有沒有都一樣
- 虛引用不能單獨使用,也不能通過虛引用獲得被引用的對象。用get()方法得到結果為null
- 為一個對象設置虛引用的唯一目的在于跟蹤垃圾回收過程。比如能在這個對象被GC時收到一個系統通知
- 虛引用必須和引用隊列一起用。因為當這個對象被GC時,這個虛引用會放到引用隊列里。
- 由于虛引用可以跟蹤對象的回收時間,因此也可以將一些資源釋放操作放在虛引用中執行和記錄
- 終極器引用