java內存泄露具體解釋


非常多人有疑問,java有非常好的垃圾回收機制,怎么會有內存泄露?事實上是有的,那么何為內存泄露?在Java中所謂內存泄露就是指在程序執行的過程中產生了一些對象,當不須要這些對象時,他們卻沒有被垃圾回收掉,並且程序執行中非常難發現這個對象。它始終占領着內存卻沒有發揮作用。

我舉這樣一個樣例,在現實開發中我們須要自己定義一個先進后出的棧集合,代碼例如以下:

package cn.lmj.demo2;

import java.util.ArrayList;
import java.util.List;

public class MyStack
{
	private List list = new ArrayList();
	private int len = 0;
	public void put(T obj)
	{
		list.add(obj);
		len++;
	}
	
	public T pop()
	{
		int index = --len;
		return list.get(index);
	}
	
}
這個代碼看起來和執行起來都沒問題,可是,這里有個非常隱晦的問題,就是在pop()方法里面。我們首先找到集合最后一個元素的下標。然后依照下標從集合中取出,可是這個對象真的從集合中移走了嗎?答案不是的,也就是說你取出來的對象看似從棧中取出來了。可是它卻還存在於集合中占領着內存。並且你非常難發現它,這就產生了內存泄露,正確的pop()方法應該是

public T pop()
{
int index = --len;
return list.remove(index);   //取出的同一時候刪除集合中的元素
}

在java中,還有這樣一個場景也會出現內存泄露問題,並且也是非常隱晦的,我們在用Map存一對鍵值型的數據時。我們假設存進去了,那么就不要改動Map的key值參與計算的hashCode方法和equals方法,例如以下代碼就有內存泄露問題:

package cn.lmj.demo2;

import java.util.HashMap;
import java.util.Map;

public class Demo03
{
	public static void main(String[] args)
	{
		Map map = new HashMap();
		Person p1 = new Person("aaa");
		Person p2 = new Person("bbb");
		Person p3 = new Person("ccc");
		map.put(p1,"1");
		map.put(p2,"2");
		map.put(p3,"3");
		System.out.println(map.containsKey(new Person("aaa")));//true
		p1.setName("eee");  //改變參與計算的hashCode和equals值
		System.out.println(map.containsKey(new Person("aaa")));//false
	}
}

class Person
{
	private String name;

	public Person(String name)
	{
		super();
		this.name = name;
	}

	public Person()
	{
		super();
	}

	//利用name屬性生成hashCode和equals方法
	@Override
	public int hashCode()
	{
		final int prime = 31;
		int result = 1;
		result = prime * result + ((name == null) ?

0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } public String getName() { return name; } public void setName(String name) { this.name = name; } }

總結:

在java中是有內存泄露的情況。那么我們在開發中怎樣避免內存泄露?除了上面兩種情況的以外:

1、最主要的建議是盡早釋放無用對象的引用。如:
  …..

  A a = new A()。

  //應用a對象

  a = null。 //當使用對象a之后主動將其設置為空
  …

  注:假設a 是方法的返回值,不要做這種處理。否則你從該方法中得到的返回值永遠為空,並且這種錯誤不易被發現、排除

  2、盡量少用finalize函數。它會加大GC的工作量。

  3、假設須要使用經經常使用到的圖片。能夠使用soft應用類型。

它盡可能把圖片保存在內存中

  4、注意集合數據類型,包含數組、樹、圖、鏈表等數據結構,這些數據結構對GC來說。回收更為復雜。

  5、盡量避免在類的默認構造器中創建、初始化大量的對象,防止在調用其自類的構造器時造成不必要的內存資源浪費

  6、盡量避免強制系統做垃圾內存的回收。增長系統做垃圾回收的終於時間

  7、盡量避免顯式申請數組空間

  8、盡量做遠程方法調用類應用開發時使用瞬間值變量。除非遠程調用端須要獲取該瞬間值變量的值。



  9、盡量在合適的場景下使用對象池技術以提高系統性能。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com