1. 程式人生 > >java應用效能調優之詳解System的gc垃圾回收方法

java應用效能調優之詳解System的gc垃圾回收方法

一、什麼是System.gc()?

System.gc()是用Java,C#和許多其他流行的高階程式語言提供的API。當它被呼叫時,它將盡最大努力從記憶體中清除垃圾(即未被引用的物件)。名詞解釋:GC,Garbage Collection,垃圾回收,下文會經常使用。

二、誰可以呼叫System.gc()?

 System.gc() 可以從應用程式堆疊的各個部分呼叫:

  • 您自己開發的應用程式可以顯式的呼叫 System.gc() 方法。
  •  System.gc() 也可以由您的第三方庫,框架觸發。
  • 可以由外部工具(如VisualVM)通過使用JMX觸發
  • 如果您的應用程式使用了RMI,RMI會定期呼叫 System.gc() 。

三、呼叫System.gc()有什麼弊端?

當 System.gc() 或 Runtime.getRuntime().gc()API被呼叫時,將觸發完整的GC事件。在GC完成之前,整個JVM將凍結(即正在執行的所有服務將被暫停),通常完整的GC需要很長時間才能完成。因此在不合適的時間執行GC,將導致不良的使用者體驗,甚至是崩潰。
JVM具有複雜的演算法,該演算法始終在後臺執行,進行所有計算以及有關何時觸發GC的計算。當您顯式呼叫System.gc()呼叫時,所有這些計算都將被拋掉。

四、哪些場景適合顯式呼叫System.gc()?

GC操作應該由JVM自行控制,在絕大部分的場景都不建議程式設計師手動寫程式碼顯式進行System.gc()操作,但是也不排除其中個別例外:在我們開發多個微服務時,每個服務都有多個備份節點。在非業務高峰時段,我們可以從微服務-負載均衡的節點池中取出其中一個JVM例項。然後通過該JVM上的JMX顯式觸發System.gc()呼叫,一旦GC事件完成並且從記憶體中清除了垃圾,將該JVM放回到微服務-負載均衡的節點池中。
當然這個過程需要很好的微服務管理及服務釋出機制配合,這樣既能保證JVM垃圾記憶體的有效清理,又不影響業務的正常執行。

五、如何檢測您的應用程式正在進行System.gc()?

如第二小節所講: System.gc() 可以從多個渠道進行的呼叫,而不僅僅是從您的應用程式原始碼進行的呼叫。因此,搜尋您的應用程式程式碼System.gc() 字串,不足以知道 GC是否正在被呼叫。這就構成了一個挑戰:如何檢測應用程式是否正在進行垃圾回收?這就是GC日誌派上用場的地方。

// java 8 啟用GC日誌:
// -XX:+PrintGCDetails -Xloggc:<gc-log-file-path> ,例如下面這行程式碼
-XX:+PrintGCDetails -Xloggc:/opt/tmp/myapp-gc.log

// java 9 啟用GC日誌:-Xlog:gc*:file=<gc-log-file-path> ,例如下面這行程式碼
-Xlog:gc*:file=/opt/tmp/myapp-gc.log

建議始終在所有生產伺服器中始終啟用GC日誌,因為它有助於您排除故障並優化應用程式效能。啟用GC日誌只會增加微不足道的開銷。還可以將您的GC日誌上傳到垃圾收集日誌分析器工具,例如GCeasy,HP JMeter等。這些工具將生成豐富的垃圾收集分析報告。

上圖摘自GCeasy生成的報告。

六、如何禁止GC顯式呼叫或調整呼叫GC的頻率?

如果我們就是想避免程式設計師顯式呼叫GC,避免不成熟的程式設計師在不合適時間呼叫GC,避免人為造成的GC崩潰,該怎麼辦?可以通過如下方法:

搜尋和替換

在程式碼庫中搜索 System.gc() 和Runtime.getRuntime().gc()。如果看到匹配項,則將其刪除。但是這種方法無法避免第三方庫、框架或通過外部源進行呼叫,那麼參考第二種方法。

通過JVM引數強制禁止

通過傳遞JVM引數  -XX:+DisableExplicitGC來強制禁止顯式呼叫。這種方式強制、有效,應用程式內的任何GC顯式程式碼呼叫System.gc() 都將被禁止生效。JVM自身的GC策略不受此引數影響,只禁止人為的觸發GC。

RMI

如果您的應用程式正在使用RMI,則可以控制GC呼叫的頻率 。啟動應用程式時,可以使用以下JVM引數配置該頻率:

  •  -Dsun.rmi.dgc.server.gcInterval=n
  •  -Dsun.rmi.dgc.client.gcInterval=n

這些屬性的預設值在

  • JDK 1.4.2和5.0是60000毫秒(即60秒)
  • JDK 6和更高版本是3600000毫秒(即60分鐘)

如果您的應用主機記憶體資源非常富餘,您可以將這些屬性設定為很高的值,以便可以將GC帶來的對應用程式的影響最小化。這也是應用程式效能優化的一種方式之一。

期待您的關注

  • 博主最近新寫了一本書:《手摸手教您學習SpringBoot系列-16章97節》
  • 本文轉載註明出處(必須帶連線,不能只轉文字):字母哥部落格。