Twitter 工程師談 JVM 調優
一. 調優需要關注的幾個方面
- 記憶體調優
- CPU 使用調優
- 鎖競爭調優
- I/O 調優
二. Twitter 最大的敵人:延遲
導致延遲的幾個原因?
- 最大影響因素是 GC
- 其他的有:鎖和執行緒排程、I/O、演算法資料結構選取不當效率低
三. 記憶體效能調優
(1)記憶體佔用調優
OutOfMemoryError 異常原因:可能真的資料量太大、可能要資料顯示的太多、可能記憶體洩露
資料量太大觀察及解決:
- 檢視 GC 日誌, 看 Full GC 前後記憶體變化, 變化不大說明確實資料量太大
- 嘗試增加 JVM 的記憶體使用
- 考慮這些資料是否真的需要都在記憶體中嗎? 可以考慮使用: LRU 演算法換入換出等, 弱引用(Soft References)
資料臃腫(Fat data)
- 當你想做一些奇怪的事情時候回發生資料佔用太大問題,比如:把整個社交圖譜載入到單個 JVM 例項上、載入全部使用者的後設資料到單個 JVM 例項上
- 在 Twitter 這樣大的規模下減少內部資料呈現工作
資料臃腫原因:
(1)物件頭(JVM 物件頭一般佔用兩個機器碼,在 32-bit JVM 上佔用 64bit, 在 64-bit JVM 上佔用 128bit 即 16 bytes, 例如:new java.lang.Object() 佔用 16 bytes; new byte[0] 佔用 24 bytes) 更多物件頭內容參考:http://blog.csdn.net/wenniuwuren/article/details/50939410
(2)填充補全
看個例子
public static class D { byte d1; } public static class E extends D { byte e1; }
new D() 佔用 24 bytes 空間, new E() 佔用 32 bytes 空間。 具體空間計算參考:http://blog.csdn.net/wenniuwuren/article/details/50958892
現在一般是 64-bit 的 JVM,64-bit 的指標會導致 CPU 快取相比 32-bit 指標減少很多, 所以建議 JVM 引數加入 -XX:+UseCompressedOops 採用指標壓縮將 64-bit 指標壓縮為 32-bit, 但是卻又能使用 64-bit 的記憶體空間, 達到一舉兩得的作用。另外,建議最大堆小於 30G。
儘量別使用原始型別物件的包裝類
在 Scala 2.7.7 中:Seq[Int] 存 Integer,Array[Int] 存 int, 第一個空間佔用 (24 + 32*length) bytes,第二個空間佔用 (24 + 4*length) bytes。
在 Scala 2.8 中修復了這個問題, 從這我們可以看出:
- 你不清楚你所使用類庫的效能特徵(比如能用 int 就用 int)
- 除非在效能分析工具下執行, 否則你可能永遠不知道這個問題
Map 空間佔用(Map footprints)
- Guava MapMaker.makeMap() 佔用 2272 bytes
- MapMaker.concurrencyLevel(1).makeMap() 佔用 352 bytes
小心使用 Thread Local
典型的問題線上程池 m*n 的資源相關,如 200 執行緒池使用了 50 個連線,最終有 10000 個連線快取
考慮使用同步物件或者每次新建一個物件
四. 與延遲做鬥爭
效能三角
圖1:記憶體佔用下降,延遲下降,吞吐量上升
圖2:壓縮(Compactness,即減小記憶體佔用)率上升,吐量上升,響應速度上升
新生代是如何工作的?
- 所有新物件分配在 Eden 代,因為新生代 GC 有壓縮,所以記憶體分配用指標碰撞
- 當 Eden 滿的時候,進行一次 stop-the-world 的 Minor GC,存活下來的放到 Survivor
- 經過幾次 Minor GC,還存活下來的物件會被提升(tenured)到老年代
理想化得新生代操作
- Eden 代足夠容納超過一組併發的請求和響應物件(這樣沒有 stop-the-world,吞吐量會比較高)
- 每個 Survivor 空間足夠容納活躍物件和有年齡的物件(減少過早提升到老年代)
- 提升閾值正好能讓存活時間長的物件早點提升到老年代(給 Survivor 騰出空間)
從新生代開始調優
- 列印詳細 GC 日誌, 如開啟 JVM 引數:-XX:+PrintGCDetails,-XX:+PrintGCDateStamps,-XX:+PrintHeapAtGC,-XX:+PrintTenuringDistribution 等等…
- 關注 Survivor 大小,設定合適的 Survivor 大小
- 關注提升閾值,使長期存活物件快速提升到老年代
(1)-XX:+PrintHeapAtGC
Heap after GC invocations=1 (full 0): par new generation total 943744K, used 54474K [0x0000000757000000, 0x0000000797000000, 0x0000000797000000) eden space 838912K, 0% used [0x0000000757000000, 0x0000000757000000, 0x000000078a340000) from space 104832K, 51% used [0x00000007909a0000, 0x0000000793ed2ae0, 0x0000000797000000) to space 104832K, 0% used [0x000000078a340000, 0x000000078a340000, 0x00000007909a0000) concurrent mark-sweep generation total 1560576K, used 0K [0x0000000797000000, 0x00000007f6400000, 0x00000007f6400000) concurrent-mark-sweep perm gen total 159744K, used 38069K [0x00000007f6400000, 0x0000000800000000, 0x0000000800000000) }
(2)-XX:+PrintTenuringDistribution
Desired survivor size 53673984 bytes, new threshold 4 (max 6) - age 1: 9165552 bytes, 9165552 total - age 2: 2493880 bytes, 11659432 total - age 3: 6817176 bytes, 18476608 total - age 4: 36258736 bytes, 54735344 total : 899459K->74786K(943744K), 0.0654030 secs] 1225769K->401096K(2504320K), 0.0657530 secs] [Times: user=0.55 sys=0.00, real=0.07 secs]
CMS 調優
- CMS 收集器需要更多的記憶體, 儘量多分配就對了
- 減少碎片、避免 Full GC
- -XX:CMSInitiatingOccupancyFraction=n n一般設定為 75-80(太早啟動降低吞吐量,太晚啟動導致 concurrent mode failed)
響應速度還是太慢?
- Minor GC 時有太多存活物件,嘗試減少新生代空間,減少 Survivor 空間,減少晉升閾值
- 太多執行緒。嘗試找到最小的併發層次或者增加更多 JVM 例項
- 嘗試使用 Volatile 而不是 synchronized 減少鎖競爭,嘗試使用 Atomic* 的原子類
用分配 slab 應對 CMS 的碎片問題
Apache 的 Cassandra 內部使用 slab 分配。每個 slab 大小為 2MB,使用 CAS 複製 byte[] 到裡面,使用 Cassandra 前開銷為 30-60 秒每小時, 使用後在3天零十小時開銷 5 秒。
使用分配 slab 的方式有一些侷限性:在快取滿的時候才把快取內容寫進磁碟,而且物件需要轉化為二進位制等問題。
相關文章
- JVM調優淺談JVM
- JVM調優JVM
- JVM調優總結-調優方法JVM
- JVM調優策略JVM
- 淺談JVM整體架構與調優引數JVM架構
- JVM調優總結(十)-調優方法JVM
- JVM調優推薦JVM
- jvm系列(七):jvm調優-工具篇JVM
- JVM調優:HotSpot JVM垃圾收集器JVMHotSpot
- JVM 調優命令&工具使用JVM
- JVM 引數調優(qbit)JVM
- JVM調優-學習篇JVM
- "簡單"的jvm調優JVM
- “簡單”的jvm調優JVM
- JVM 調優(學習篇)JVM
- JVM常用調優引數JVM
- Java jvm 診斷調優JavaJVM
- JVM 調優示例和配置JVM
- 【JVM進階之路】十:JVM調優總結JVM
- JVM調優工具Arthas的使用JVM
- JVM原理講解和調優JVM
- JVM常用調優工具介紹JVM
- 深入理解JVM效能調優JVM
- JVM調優總結(十一)-反思JVM
- 簡單JVM調優經歷JVM
- 第37篇 JVM調優方式JVM
- 淺談Oracle調優Oracle
- jvm系列(六):jvm調優-從eclipse開始JVMEclipse
- 《java學習三》jvm效能優化-------調優JavaJVM優化
- 【深入理解JVM】8、JVM實戰調優+GC演算法+JVM調優如何定位問題+常見的定位JVM優化命令【面試必備】JVMGC演算法優化面試
- 探探Java之 JVM GC與調優JavaJVMGC
- JVM效能調優與實戰篇JVM
- 大型跨境電商JVM調優經歷JVM
- 淺談Nginx效能調優Nginx
- websphere MQ調優淺談WebMQ
- 《沙盤模擬系列》JVM如何調優JVM
- JVM調優:基本垃圾回收演算法JVM演算法
- 跟著練、包會(JVM調優工具)JVM