內存泄露:指程序中動態分配內存給一些臨時對象,可是對象不會被GC所回收,它始終佔用內存。即被分配的對象可達但已無用。
內存溢出:指程序運行過程當中沒法申請到足夠的內存而致使的一種錯誤。內存溢出一般發生於OLD段或Perm段垃圾回收後,仍然無內存空間容納新的Java對象的狀況。
從定義上能夠看出內存泄露是內存溢出的一種誘因,可是不是惟一因素。java
Runtime.getRuntime().freeMemory()表示當前還有多少空閒內存數據庫
package com.one.util; public class Hello { public static void main(String[] args) { System.out.println("free內存:" + Runtime.getRuntime().freeMemory() / 1024 / 1024); String[] aaa = new String[2000000]; for (int i = 0; i < 2000000; i++) { aaa[i] = new String("aaa"); } System.out.println("free內存:" + Runtime.getRuntime().freeMemory() / 1024 / 1024); } }
此時結果以下所示
網絡
好比下面的代碼,這裏的object實例,其實咱們指望它只做用於method1()方法中,且其餘地方不會再用到它,可是,當method1()方法執行完成後,object對象所分配的內存不會立刻被認爲是能夠被釋放的對象,只有在Simple類建立的對象被釋放後纔會被釋放,嚴格的說,這就是一種內存泄露。socket
public class Simple { Object object; public void method1(){ object = new Object(); //...其餘代碼 } }
怎麼解決上面的問題呢,加上下面的藍色代碼註釋就行了ide
public class Simple { Object object; public void method1(){ object = new Object(); //...其餘代碼 // 藍色代碼註釋開始 object = null; // 藍色代碼註釋結束 } }
好比下面的代碼
由於你已經在下面的藍色代碼註釋裏面進行company=null了,因此下面的list集合裏面的數據都是無用的了,可是此時list集合裏面的全部元素都不會進行垃圾回收測試
package com.four; import java.util.ArrayList; import java.util.List; public class Hello { public static void main(String[] args) { List<Company> list = new ArrayList<Company>(); int i=0; for(int j=0;j<10;j++){ Company company = new Company(); company.setName("ali"); list.add(company); // 藍色代碼註釋開始 company = null; // 藍色代碼註釋結束 } System.gc(); while(true){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("已經測試了"+(++i)+"秒"); } } } class Company { private String name; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("回收Comapny"); } public void setName(String name) { this.name = name; } public String getName() { return name; } }
怎麼解決上面的問題呢,就是把上面的list集合變量也變成null,好比加上下面的紅色代碼註釋this
package com.one.util; import java.util.ArrayList; import java.util.List; public class Hello { public static void main(String[] args) { List<Company> list = new ArrayList<Company>(); int i = 0; for (int j = 0; j < 10; j++) { Company company = new Company(); company.setName("ali"); list.add(company); // 藍色代碼註釋開始 company = null; // 藍色代碼註釋結束 } // 紅色代碼註釋開始 list = null; // 紅色代碼註釋結束 System.gc(); while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("已經測試了" + (++i) + "秒"); } } } class Company { private String name; @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("回收Comapny"); } public void setName(String name) { this.name = name; } public String getName() { return name; } }
此時結果以下所示,能夠看出來集合裏面的Company變量都回收了
code
什麼意思呢,
就好比ArrayList裏面的pop(),若是是下面的寫法就會形成內存泄漏,由於下面的elementData[--size]這個元素移除以後,並無進行設置成null對象
public E pop(){ if(size == 0) return null; else return (E) elementData[size]; }
因此上面的代碼應該變成下面這樣,此時注意下面的藍色代碼註釋裏面的size值比下面的紅色代碼註釋裏面的size小1blog
public E pop(){ if(size == 0) return null; else{ // 紅色代碼註釋開始 E e = (E) elementData[--size]; // 紅色代碼註釋結束 // 藍色代碼註釋開始 elementData[size] = null; // 藍色代碼註釋結束 return e; } }
好比數據庫鏈接(dataSourse.getConnection()),網絡鏈接(socket)和io鏈接,這些連接在使用的時候,除非顯式的調用了其close()方法(或相似方法)將其鏈接關閉,不然是不會自動被GC回收的。其實緣由依然是長生命週期對象持有短生命週期對象的引用。因此咱們常常在網上看到在鏈接調用結束的時候要進行調用close()進行關閉,這樣能夠回收不用的內存對象,增長可用內存。
能看到這裏的同窗,就幫忙點個推薦吧吧,Thanks♪(・ω・)ノ