一、什么是內存泄漏
開發中,都能遇到或者聽過兩種關於java內存的異常情況:內存溢出(out of memory)和內存泄漏(memory leak)。
內存溢出指的是程序需要申請新的內存時,沒有足夠大小的內存空間供其使用。常見類型:
1、java.lang.OutOfMemoryError: Java heap space 堆內存溢出 解決辦法:通過-Xmn(最小值)–Xms(初始值) -Xmx(最大值)參數手動設置 Heap(堆)的大小
2、 java.lang.StackOverflowError 棧溢出 解決辦法:通過Xss參數調整大小
3、 java.lang.OutOfMemoryError: PermGen space 解決辦法:通過MaxPermSize參數設置PermGen space大小
內存泄漏指的是程序申請內存后,當不再使用時,本該被回收卻始終無法釋放或是不能及時的釋放已申請的內存空間。內存泄漏,如果數量龐大,最終是會導致內存溢出的。
對用戶來說,內存泄漏並不會產生什么危害。程序代碼、運行對用戶是完全透明的,真正的危害性在於內存泄漏可能導致的最終的內存溢出,程序崩潰終止。
這里,java開發人員一般會有疑問:既然java存在GC,為什么還會發生內存泄漏?
簡單說說GC的回收:
java GC會監控所有堆中創建的對象的運行狀況,監控對象是否可達(從GC Roots根開始向下搜索),如果對象不可達,則其就可以被GC回收。GC由jvm自動執行,不可人為干預(System.gc()方法只是建議jvm去執行回收動作,並不能確定一定會即時的去執行)
內存泄漏為什么發生:
實際的開發過程中,可能會存在着無用但可達的對象,這些對象不能被GC回收,所以就導致了內存泄漏的產生。
二、java中案例
1、靜態集合類中存儲對象
static List<Object> list = new ArrayList<>(); public static void main(String[] args) { for(int i =0; i<10; i++){ Object object = new Object(); list.add(object); object = null; } }
靜態集合類中,循環申請對象放入集合中。后面僅僅是對新申請的對象置null,並不能引起GC對於這個對象的回收,因為集合類仍然對其保持着引用,
也就是可達的(list引用指向的內存空間中存在指向 Object 對象的引用)。如果后面的程序中,不再使用集合list,則這就產生了內存溢出。一般好的習慣,不使用的集合clear,然后置為null。
2、單例模式
單例的生命周期和應用程序是一樣長的,所以單例程序中,如果持有對外部對象的引用的話,那么這個外部對象是不能被回收的,則會導致內存泄漏的產生。
3、一些提供close的資源未關閉導致內存泄漏
數據庫連接(dataSourse.getConnection()),網絡連接(socket)和io連接必須手動close,否則是不能被回收的。