1. 程式人生 > >JVM1小時1次FGC調優

JVM1小時1次FGC調優

通過cat發現專案一個奇怪現象,每隔一個小時都會進行一次fgc,很有規律,且和專案使用高低峰無關。最開始以為是記憶體洩漏。通過觀察,發現線下研發環境也一樣,fgc時堆的年輕代,年老代,持久代的記憶體都未佔滿,應該不是記憶體洩漏問題。開始懷疑專案中使用了JMX監控zookeeper狀態時,保留了JMXConnector的連線物件。研發環境把這塊去掉,觀察發現沒有fgc問題。問題找到了,上網搜了下,果然有前輩遇到過有現成的解決方案:

引發的原因是由於使用了RMI,會自動1小時呼叫1次system.gc()。

  大多數的應用雖然配置了CMS gc方式,但是如果沒有使用-XX:+ExplicitGCInvokesConcurrent,則會出現顯示呼叫system.gc(),且不會進行 CMS的FGC,帶來的影響是造成tps的波動(fgc停機時間越長,則波動會越大)。   收集各方的意見後,總結針對此類問題的解決方法如下:   1、增加引數 -XX:+DisableExplicitGC
  該方法System.gc()的呼叫就會變成一個空呼叫。但是該方法不適用在大量使用NIO的direct memory,經常、反覆的申請DirectByteBuffer的應用中使用,會造成“java.lang.OutOfMemoryError: Direct buffer memory ”。該方法需根據應用具體情況而定。   2、增加引數 -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000   其中3600000即為定時觸發的時間間隔設定,單位是毫秒,可適當延長觸發FGC的定時時間間隔。   -Dsun.rmi.dgc.client.gcInterval=Long.MAX_VALUE     -Dsun.rmi.dgc.server.gcInterval=Long.MAX_VALUE 則將fc時間間隔設為long型的最大值   3、增加引數 -XX:+ExplicitGCInvokesConcurrent 或者-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
  該方法可以指定System.gc()採用 CMS 演算法,FGC時停機時間會變短,但是CMS GC次數不會變,仍然是1小時1次。 根據專案線上GC的記憶體狀況,結合2和3增加虛擬機器引數:

-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses -Dsun.rmi.dgc.client.gcInterval=36000000 -Dsun.rmi.dgc.server.gcInterval=36000000

考慮使用ExplicitGCInvokesConcurrentAndUnloadsClasses而不是ExplicitGCInvokesConcurrent,擔心有通過反射等方式載入的類之後並未被使用,還有通過maven傳遞依賴過來的jar包太多,有很多也許執行時並未用到,能通過垃圾回收會清理持久代中不再使用的classes。如果之後發現有執行時類找不到的錯誤,則再改回ExplicitGCInvokesConcurrent

。10小時觸發一次(這個時間設定需要觀察堆記憶體的狀態變化)。-Dsun.rmi.dgc.client.gcInterval=36000000這個其實可以不配的,伺服器預設都是配置-server的。

之所以不用1方案,遮蔽System.gc()還是有風險的。