Java 程序優化知識筆記

編程語言 Java Java虛擬機 腳本語言 後端開發那點事兒 2017-04-02

Java 程序優化知識筆記

Java 程序優化知識筆記

遷移 64 位虛擬機未必性能更好

業務量上升以後,需要使用的內存隨之增加,而在通常 32 位系統上,單個進程佔用的最大內存通常是 2GB,且考慮到堆外內存的使用,32 位機器可能無法滿足內存要求,一種常見的應對方式就是換用 64 位服務器。而對於 Java,由於指針膨脹和字節對齊,同一個程序在 64 位虛擬機上佔用的內存會多於 32 位虛擬機。開發者換用 64 位虛擬機後,很可能會增加虛擬機的堆大小,而這將導致 Full GC 垃圾回收的時間大大增加,導出堆快照也變得困難。

因此,使用 64 位虛擬機增加內存時,需要特別注意對內存的使用,儘量不要觸發 Full GC 導致長時間停頓。另一種方法是建立 32 位虛擬機的集群來提高性能。

堆外內存溢出

Java 本地方法調用,如調用 C++ 實現的本地模塊、NIO 的 DirectByteBuffer,都會佔用大量內存。而在開發中,開發者往往重點關注了堆內存的大小,在內存溢出時也傾向於增加堆內存,而忽視了堆外內存的使用。堆外內存並不會像堆內存一樣不足馬上通知 GC 進行垃圾回收,堆外內存只能等待老年代空間不足進行 Full GC 時順便回收內存,否則堆外內存只能等到空間不足時拋出內存溢出異常,然後請求 GC 進行回收。

因此,配置虛擬機,除考慮常規的堆大小外,優化時還需要考慮 Direct Memory、線程棧、socket 緩衝區、JNI 代碼、虛擬機、GC 佔用的內存大小。

外部命令的時間消耗

Java 開發中如果需要執行 shell 腳本,可以使用 Runtime.getRuntime().exec 方法,還能從返回的 Process 對象中讀取標準輸出、錯誤輸出、等待執行結束。根據方法註釋,該方法首先複製當前進程產生一個子進程,在子進程中執行命令,結束後退出子進程。

進程的複製比較消耗 CPU 和內存,應儘量通過 Java 程序本身去完成相關功能。

多線程使用線程池

Java 虛擬機中沒有給用戶用的多進程方法,並行處理更多地使用多線程方式。默認情況下,Linux 限制用戶的線程數量上限為 1024,當然包括了系統中運行的所有線程。通常情況下,線程資源不會被耗盡,但多線程程序如果頻繁創建新線程也會遇到線程資源不足的情況。一方面,可以調整系統設置,提高線程數上限,另一方面,應儘量避免頻繁創建線程。線程雖小,創建時一樣要消耗時間和內存。

多線程程序應儘量採用 Java 的線程池,這樣線程的個數總體可控,使用時可以避免創建線程的時間消耗。Java 提供了多種功能強大的線程池類型,基於線程池可以對任務進行緩存、按照一定的時間頻率執行任務、返回執行結果、分叉與合併等。

每週 3 篇學習筆記或技術總結,面向有一定基礎的 Java 程序員,內容涉及 Java 進階、虛擬機、MySQL、NoSQL、分佈式計算、開源框架等多個領域。關注作者或微信公眾號 backend-develop 第一時間獲取最新內容。

相關推薦

推薦中...