
什麽是Java中的內存泄漏
通常,當應用程序不再使用對象時,應該對這些對象進行垃圾回收。但是,如果仍然引用這些對象,則垃圾回收器無法從工作內存中刪除這些對象。此外,在應用程序的整個生命周期中,還有一些對象保留在內存中(例如:靜態變量)。因此,此類應用程序消耗越來越多的內存,並導致OOM(Out Of Memory)問題。
內存泄漏與生產係統
在wso2中,我幾乎沒有分析某些生產係統中的內存泄漏的經驗。生產係統中發生內存泄漏的可能性很高,因為這些係統運行較長時間而沒有重啟。在這種情況下,即使內存泄漏很小,它也會累積泄漏,最後可能會導致嚴重的內存泄漏。這樣的內存泄漏很難在本地重新創建,但是我們可以嘗試通過使係統長時間保持負載運行來嘗試複現問題。
內存泄漏的原因
內存泄漏的主要原因是不良的編程。
- 大量使用靜態變量
在靜態類中,可以使用類成員而不啟動類。因此,在使用static時,在創建類實例之前,將在JVM中創建其類的對象。因此,此類靜態變量將在程序執行期間保留在內存中,不符合垃圾回收的條件。 - 未關閉的流/連接
這將導致底層資源泄漏和內存泄漏。底層資源泄漏一般是由操作係統級資源的泄漏。 JVM使用內存來跟蹤這些基礎資源,從而導致內存泄漏。
未關閉流和連接的主要原因是:因為開發人員忘記了關閉打開的流/連接。在Java 7之後,我們有了try-with-resources,不用手動關閉流。 - 具有缺少 hashCode()或 equals()實現的對象的Hashset。如果我們不重寫 hashCode()和 equals()方法並嘗試將重複條目添加到集合中,則將無法識別重複項,而是將多個重複項添加到集合中。而且,一旦添加副本,就無法刪除這些重複副本。
什麽是堆轉儲(heap dump)
堆轉儲是某個特定時間點Java進程內存的快照。觸發快照時,堆轉儲包含Java對象和類。
為什麽我們需要分析堆轉儲
堆轉儲分析有助於找到對象的創建位置,並在源中找到對這些對象的引用。該調查的最終目標是找到消耗過多內存的對象以及正在運行的應用程序中這些對象的存放位置。
如何分析堆轉儲
1.在基線和高流量中捕獲堆轉儲。這意味著當係統運行正常且流量很高時,我們需要進行兩個堆轉儲。
命令:
jmap-dump:format=b,file=<file-path><pid>
其中pid:是Java進程ID,我們要捕獲其堆轉儲。 file-path:是堆轉儲將寫入數據的文件路徑。
2.在係統崩潰之前捕獲堆轉儲
由於很難確定係統崩潰的地點,因此我們可以使用以下命令在這種情況下獲取堆轉儲。建議您始終在所有應用程序中都配置此屬性,因為我們不知道何時發生OOM錯誤。
XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<file-path>
file-path:是堆轉儲將寫入的文件路徑。
java -XX:+ HeapDumpOnOutOfMemoryError
3.確定在步驟1和步驟2之間大小在增長的對象。
幾個內存分析工具
- MAT
- Java Flight Recorder
- Eclipse內存分析器
- IBM HeapAnalyzer