增長堆內存的大小 - 提防眼鏡蛇效應

增長堆內存的大小 - 提防眼鏡蛇效應 java

原文:http://plumbr.eu/blog/increasing-heap-size-beware-of-the-cobra-effect 緩存

"眼鏡蛇效應"起源於當時英國統治印度殖民地的軼事。英國政府關心一些有毒的眼鏡蛇.因此政府對每條死蛇提供獎勵.最初這個方案很成功爲了獎勵大量的毒蛇被殺死.然而最終印度人爲了收入開始養殖眼鏡蛇.

當意識到獎勵取消了,養殖眼鏡蛇和野生眼鏡蛇成倍增長了. 明顯的這個問題解決方案使這個狀況更糟了.

如何調整Java堆內存的大小就像殖民地印度和毒蛇的關係.多包涵,我會引導你經過這個比喻用一個故事從現實生活中做爲參考。

你已經建立了一個強大的程序. 如此強大使程序變的真正的流利和有巨大的流量,新的服務開始添加到你的程序中.經過挖掘你決定的性能指標,你程序的可用堆內存將不久成爲瓶頸.

所以你部署了是原來6倍堆內存的基礎設施. 你測試你的程序驗證它能夠工做.你部署它到新的硬件上.可是當即開始抱怨下面的問題 - 你的程序變的比之前2GB堆內存時響應要慢. 你的一些用戶面臨着分等待你的程序的響應延遲幾分鐘. 發生了什麼?

能夠有不少緣由.不過,讓咱們關注最有可能發生的地方 - 堆內存大小的改變.這裏有幾種很差的效果像擴展緩存的預熱時間,碎片問題等.可是從症狀上來看你最有可能面臨的是full GC期間的延遲問題.

這就意味着 - Java做爲垃圾回收類型的語言 - 你的堆內存經過JVM內部的線程有規律的進行垃圾回收.正好你所預料的 - 若是你有一個較大的空間須要清理那麼每每須要更多的時間. 一樣適合於從內存中整理未使用的對象.

當運行的程序在一個小的堆上(低於4G)你不須要考慮GC.不過當堆內存增加到數十GB你絕對應該意識到潛在的full GC引發的stop-the-world暫停. 很是相信的暫停也存在在小的堆上, 可是他們的長度明顯更短 - 你的暫停原本可能只有幾百毫秒最後會超過一分鐘.

因此當你真的須要給你的程序更多的堆內存時應該作些什麼?


1. 第一個選擇是考慮水平擴展代替垂直擴展. 對於當前的情況意味着 - 若是你的程序是無狀態的或者是容易分區的那麼只須要添加一個小的節點再對他們進行負載均衡. 這種狀況下你能夠堅持低內存佔用的32位架構.

2.  若是水平擴展不可行你應該注意你的GC配置. 若是你追求的是延遲,你就應該忘掉面向吞吐量的stop-the-world GC而且開始尋找替代者. 你很快會發現僅限於併發標記及清掃(CMS)或者G1收集器.悲劇的消息是你最好的選擇是這兩種收集器之間以及其餘只能經過嘗試去發現的堆內存的配置參數.因此不要作出選擇,去試一下你真實的生產環境負載.

此外意識到他們的侷限性 - 這兩種收集器在你的程序上形成吞吐量的系統消耗 - 特別是G1每每表現的比stop-the-world更糟的吞吐量. 而且當CMS垃圾收集器沒有足夠快的在完成收集前持久代滿了,會回退到常規的stop-the-world GC. 因此你可能仍然面對30秒或更長的暫停對於16G或更大的堆.

3.  若是你不能水平擴展或者不能實現須要的延遲結果關於在Oracle's JVM上的垃圾回收, 那你也能夠考慮經過Azul系統構建的Zing JVM.其中一個使Zing脫穎而出的特性是不中止垃圾回收(C4), 這個多是你正在尋找的.雖然徹底公開 - 不過咱們尚未在練習中嘗試C4.可是聽起來確實很棒.

4.  最後一個選擇是給那些真正的專家們. 你能夠在堆外分配內存. 那些分配的內存顯然對垃圾回收不可見所以不會被收集. 這個可能聽起來很嚇人, 其實在Java 1.4咱們訪問java.nio.ByteBuffer類,他已經提供給咱們一個方法allocateDirect()去分配堆外內存.這容許咱們建立很大的數據結構而不會形成多秒的GC暫停. 這個解決方案不太常見 - 不少BigMemory的實現是在底層使用ByteBuffers.好比Terracotta BigMemory和Apache DirectMemory.
相關文章
相關標籤/搜索