
內存泄漏
本文介紹內存泄漏是什麽以及何時運行垃圾收集器。發生內存泄漏的情況是不再使用對象,並且垃圾收集器無法將其從堆中刪除-因為仍在引用它們。結果,應用程序消耗了越來越多的資源-最終導致致命的OutOfMemoryError問題(OOM)。
內存泄漏導致OOM問題跟JVM堆設置有關,您可以通過設置參數來指定應用程序的初始和最大堆大小:
-Xms<size>
-Xmx<size>
例如:-Xms64m -Xmx512m,表示JVM以64M開頭,如果需要超過64M的內存,則增加內存(最大上限為512),超過上限則會出錯。一般內存泄漏的查找方法及解決辦法:
- 借助Eclipse檢查內存泄漏:
任何實現了可關閉即closable(從1.5開始)(例如輸出流自1.5版開始)接口的對象,如果引用被破壞但對象未關閉,則會向您發出警告。
在EclipseProject > Project settings > JAVA compiler > Errors/Warning > select leak from options(從選項中選擇泄漏)。 - 檢查代碼:
靜態字段:靜態引用持續存在,因此無法從內存中清除對象。
守護進程線程:在Web應用程序生命周期之外啟動的啟動程序容易發生內存泄漏。
關閉連接:關閉所有文件和數據庫連接可以防止內存泄漏。始終關閉連接,直到最終阻塞。
空分配:在使用列表,Map等之後將null分配給它們,也可以防止內存泄漏。
自動裝箱:每次創建一個新對象時,在傳遞給函數時,避免將原語與包裝器類混合在一起。 - 使用工具分析內存使用情況:
像 JProfiler, GC Viewer,VisualVM, JConsole 這類的工具能幫助您分析應用程序的性能。
您可以通過在附加了VisualVM的情況下運行應用程序來分析代碼。然後執行使您的應用程序變慢的任務,並分析“monitor”和“memory pools”選項卡。
查看內存使用量峰值,然後按執行GC按鈕將釋放內存。
垃圾收集
Java垃圾回收是Java程序執行自動內存管理的過程。垃圾收集器找到未引用的對象並將其刪除以釋放內存。
Java垃圾回收是一個自動過程。程序員不需要顯式標記要刪除的對象。垃圾回收的實現駐留在JVM中。
java.lang.System.gc()方法運行垃圾收集器。
根據甲骨文文檔:
主要調用gc方法隻是建議Java虛擬機花費更多精力來回收未使用的對象,以使它們當前占用的內存可用於快速重用。當從方法調用返回時,Java虛擬機將盡最大努力從所有丟棄的對象中回收空間。
調用System.gc()實際上等效於該調用:Runtime.getRuntime().gc()
一旦對象符合垃圾收集條件,它不會立即被垃圾收集器銷毀,隻有當JVM運行Garbage Collector程序時,對象才會被銷毀。但是我們不能期望JVM何時運行Garbage Collector。
注意:無法保證上述主動條用GC的方法一定會運行垃圾收集器。
有人將對象引用設置為null以使其符合gc的條件,並使用System.gc()方法顯式刪除內存。將其設置為null沒什麽大不了,但是調用System.gc()方法將極大地影響係統性能,因此最好別這麽幹!
JVM世代:
堆分為較小的幾個部分或者說幾代。具體來說,堆的組成部分是:年輕代(Young),老年代(Old, 終身一代)以及永久代(Permanent)。
- 年輕代,所有新對象被分配和並開始老化的位置。當年輕代填滿時,這會導致minor garbage collection,當老化的對象達到一定的年齡閾值時,它們將從年輕代升級為老年代。
- 老年代,用於存儲長期存在的對象。通常,為年輕代對象設置一個閾值,並且當達到該年齡時,該對象將移至老年代。這一代空間填滿內存最終會被垃圾收集。此事件稱為major garbage collection。
- 永久代,包含JVM所需的元數據,用於描述應用程序中使用的類和方法。
這是內存泄漏和垃圾收集器工作的簡單而簡短的解釋。
可以在Oracle文檔中研究GC和JVM生成的完整工作,以及如何將對象從一代移動到另一代。參考這裏