關於Java垃圾回收被誤解的7件事
對Java垃圾回收最大的誤解是什麼?它實際又是什麼樣的呢?
當 我還是小孩的時候,父母常說如果你不好好學習,就只能去掃大街了。但他們不知道的是,清理垃圾實際上是很棒的一件事。可能這也是即使在Java的世界中, 同樣有很多開發者對GC演算法產生誤解的原因——包括它們怎樣工作、GC是如何影響程式執行和你能對它做些什麼。因此我們找到了Java效能調優專家Haim Yadid,並把名為Java performance tuning guide的文章發表在Takipi的部落格上。
最新博文:關於垃圾回收被誤解的7件事
http://t.co/3QJLJuKCRqpic.twitter.com/aqQEF0zTkK
— Takipi (@takipid) April 6, 2015
帶著對效能調優指南濃厚的興趣,我們決定在這篇後續的博文中收集一些關於垃圾回收的流行觀點,並且指出為什麼它們完全是錯誤的。
來看看前7名:
1. 只有一個垃圾回收器
不,並且4也是錯誤的答案。HotSpot JVM一共有4個垃圾回收器:Serial, Parallel / Throughput. CMS, and the new kid on the block G1。別急,另外還有一些非標準的垃圾回收器和更大膽的實現,比如Shenandoah或 者其他JVM使用的回收器(C4——Azul開發的無停頓回收器)。HotSpot預設使用Parallel / Throughput回收器,但它常常不是你執行程式的最佳選擇。比如CMS和G1會使GC停頓(GC pause)發生的頻率降低,但是對於每次停頓所花費的時間,很可能比Parallel回收器更長。另一方面來說,在使用相同大小堆記憶體的情況下,Parallel回收器能帶來更高的吞吐量。
結論:根據你的需求(可接受的GC停頓頻率和持續時間)選擇合適的垃圾回收器。
2. 並行(Parallel) = 併發(Concurrent)
一個GC週期(Garbage Collection cycle)可以以STW(Stop-The-World)的形式出現,這會發生一次GC停頓,也可以併發地執行從而無需暫停應用程式。更進一步來 講,GC演算法本身可以是序列的(單執行緒),也可以是並行的(多執行緒)。因此當我們提到併發的GC時,並不代表它是並行完成的,相反當提到序列GC時,也並 不意味著就一定會出現GC停頓。在GC的世界中,併發和並行是兩個完全不同的概念。併發針對的是GC週期,而並行針對GC演算法自身。
結論:垃圾回收的過程實際上有兩步,啟動GC週期和GC自身執行,這是不同的兩件事。
3. G1能解決所有問題
經過一系列修正和改 進,Java 7中引入了G1回收器,它是JVM垃圾回收器中最新的元件。G1最大的優勢就是解決了CMS中常見的記憶體碎片問題:GC週期會從老年代(Old Generation)中釋放記憶體塊,結果記憶體變得像瑞士乳酪那樣千瘡百孔,直到JVM對其無從下手了,才不得不停下來處理這些碎片。但是故事沒這麼簡 單,某些情況下其他回收器可能比G1有更好的表現,這完全取決於你的需求。
結論:沒有一個奇蹟般的回收器能解決所有GC問題,你應該通過具體實驗來選擇合適的回收器。
4. 平均事務時間是最需要被關注的指標
如 果你僅僅監控伺服器的平均事務時間,那麼很可能錯過一些異常值。這些異常的情況可能對使用者來說是毀滅性的,而人們沒有意識到它的重要性。比如一個事務在正常情況下耗時100ms,但受到GC停頓的影響,花了1分鐘才完成。除了使用者沒人會注意到這個問題,因為你只觀察了平均事務時間。試想有1%或者更多的用 戶經歷了這個場景,如果只關注平均值,它就太容易被忽略了。想了解更多和延遲相關的問題和怎樣正確處理,可以在這裡閱讀Gil Tene的部落格。
結論:留心那些異常值,你可以知道系統最後那1%的狀況。(可不是這個1%)
5. 降低新物件的分配率可以改善GC的執行狀況
我們可以 粗略地把系統中的物件分為三種:長命(long-lived)物件,對它們我們一般做不了什麼;中等壽命(mid-lived)物件,最大的問題可能出現在這;短命(short-lived)物件,它們的釋放和回收通常都很快,在下個GC週期來臨時就會消失。專注於中等壽命物件的分配率可以帶來有益的結 果,這對短命和長命的物件卻不是那麼有效。另外,控制中等壽命物件往往是一項困難的工作。
結論:給伺服器帶來壓力的並不單純是物件的分配率,在執行過程中這些物件的種類才是一切麻煩的根源。
6. 調優可以解決所有事
如果你的程式需要儲存大量被頻繁修改的狀態,對JVM堆記憶體進行調優就無法帶來很好的收益。較長的GC停頓是不可避免的。一個解決辦 法是對架構進行改善,保證一個對響應時間有決定性影響或者造成瓶頸的過程中,不包含大量狀態。大量狀態和響應能力是難以良好共存的,因此將它們分開處理才 是上上之選。
結論:不是所有的問題都可以通過調整JVM引數解決,有時你只需要回顧自己的繪圖板。(譯註:重新審視程式的設計)
7. GC日誌會導致巨大的系統開銷
簡單來說,這是錯的,尤 其在預設的日誌配置下。日誌資料是極為有價值的,Java 7中還引入了鉤子來控制它們的大小,保證硬碟空間不被用盡。如果不收集GC日誌,那麼你會失去這幾乎是唯一的,知曉JVM垃圾回收器在生產環境中工作狀態 的方法。一般可接受的GC開銷以5%作為上限,如果你能知道系統為GC停頓付出的代價,也能對最小化這個代價採取行動,這種程度的開銷是不值一提的。
結論:在能力範圍內,儘可能多地獲取系統在生產環境中的執行資料,你會發現那是一個全新的世界。
總結
希望上面的結論能幫助你們更好地把握Java垃圾回收器的工作。在你們的程式中出現過類似問題嗎?你們周圍還有沒有其他對GC常見的誤解?請在下面的評論區留言。
相關文章
- 關於JVM的垃圾回收JVM
- jvm(4)---垃圾回收(哪些物件可以被回收)JVM物件
- 關於jvm的永久代會發生垃圾垃圾回收嗎?進來便知JVM
- Java 垃圾回收機制Java
- java垃圾回收機制Java
- 垃圾回收(一)【垃圾回收的基礎】
- Java虛擬機器詳解(三)------垃圾回收Java虛擬機
- JAVA垃圾回收機制和Python垃圾回收對比與分析JavaPython
- 12 垃圾回收相關概念
- java垃圾回收機制整理Java
- Java的垃圾回收(Garbage Collection)機制Java
- 垃圾回收(三)【垃圾回收通知】
- python進階(7)垃圾回收機制Python
- 淺析 PHP7 的垃圾回收機制PHP
- 關於Go,你可能不注意的7件事Go
- Java11改進的垃圾回收器Java
- Java 垃圾回收01(基本過程)Java
- 圖解 Java 垃圾回收機制,寫得非常好!圖解Java
- 8.19 被誤解的關鍵字:gotoGo
- Java垃圾回收機制詳解及效能最佳化詳解。Java
- 垃圾回收
- 圖解Golang垃圾回收機制!圖解Golang
- Java經典垃圾回收器介紹Java
- java垃圾回收有哪些演算法Java演算法
- Java記憶體管理 -JVM 垃圾回收Java記憶體JVM
- 7種jvm垃圾回收器,這次全部搞懂JVM
- JVM 垃圾回收演算法和垃圾回收器JVM演算法
- 關於製造業中物聯網的未來應該瞭解的7件事
- Kubernetes 中的垃圾回收
- JVM 中的垃圾回收JVM
- 聊聊Dotnet的垃圾回收
- JavaScript 中的垃圾回收JavaScript
- Java虛擬機器垃圾回收相關知識點全梳理(上)Java虛擬機
- 你必須瞭解的java記憶體管理機制(四)-垃圾回收Java記憶體
- [JVM]垃圾回收JVM
- golang垃圾回收Golang
- Python:垃圾回收Python
- JVM垃圾回收JVM
- 垃圾回收_上