Java 中記憶體是如何管理的
為了判斷Java中是否有記憶體洩露,我們首先必須了解Java是如何管理記憶體的。Java的記憶體管理就是對象的配置設定和釋放問題。在Java中,程式員需要通過關鍵字new為每個對象申請記憶體空間 (基本類型除外),所有的對象都在堆 (Heap)中配置設定空間。另外,對象的釋放是由GC決定和執行的。在Java中,記憶體的配置設定是由程式完成的,而記憶體的釋放是有GC完成的,這種收支兩條線的方法确實簡化了程式員的工作。但同時,它也加重了JVM的工作。這也是Java程式運作速度較慢的原因之一。因為,GC為了能夠正确釋放對象,GC必須監控每一個對象的運作狀态,包括對象的申請、引用、被引用、指派等,GC都需要進行監控。
監視對象狀态是為了更加準确地、及時地釋放對象,而釋放對象的根本原則就是該對象不再被引用。
下面請看示例:
public class Main{
public static void main(String args[]){
Object obj1= new Object();//obj1
Object obj2= new Object();//obj2
obj2= obj1;
//此處為第6行
}
1
2
3
4
5
6
7
8
9
記憶體的釋放,也即清理那些不可達的對象,是由GC決定和執行的,是以GC會監控每一個對象的狀态,包括申請、引用、被引用和指派等。釋放對象的根本原則就是對象不會再被使用:
`給對象賦予了空值null,之後再沒有調用過。`
`另一個是給對象賦予了新值,這樣重新配置設定了記憶體空間。`
什麼是Java中的記憶體洩露
Java中的記憶體洩露,廣義并通俗的說,就是:不再會被使用的對象的記憶體不能被回收,就是記憶體洩露。
Java中的記憶體洩露與C++中的表現有所不同。
在C++中,所有被配置設定了記憶體的對象,不再使用後,都必須程式員手動的釋放他們。是以,每個類,都會含有一個析構函數,作用就是完成清理工作,如果我們忘記了某些對象的釋放,就會造成記憶體洩露。
但是在Java中,我們不用(也沒辦法)自己釋放記憶體,無用的對象由GC自動清理,這也極大的簡化了我們的程式設計工作。但,實際有時候一些不再會被使用的對象,在GC看來不能被釋放,就會造成記憶體洩露。
&emspl;通過分析,我們得知,對于C++,程式員需要自己管理邊和頂點,而對于Java程式員隻需要管理邊就可以了(不需要管理頂點的釋放)。通過這種方式,Java提高了程式設計的效率。
是以,通過以上分析,我們知道在Java中也有記憶體洩漏,但範圍比C++要小一些。因為Java從語言上保證,任何對象都是可達的,所有的不可達對象都由GC管理。
下面給出了一個簡單的記憶體洩露的例子。在這個例子中,我們循環申請Object對象,并将所申請的對象放入一個Vector中,如果我們僅僅釋放引用本身,那麼Vector仍然引用該對象,是以這個對象對GC來說是不可回收的。是以,如果對象加入到Vector後,還必須從Vector中删除,最簡單的方法就是将Vector對象設定為null。
Vector v=new Vector(10);
for (int i=1;i<100; i++){
Object o=new Object(http://www.my516.com);
v.add(o);
o=null;
//此時,所有的Object對象都沒有被釋放,因為變量v引用這些對象。
如何防止記憶體洩漏的發生?
好的測試工具
在開發中不能完全避免記憶體洩漏,關鍵要在發現有記憶體洩漏的時候能用好的測試工具迅速定位問題的所在。市場上已有幾種專業檢查 Java 記憶體洩漏的工具,它們的基本工作原理大同小異,都是通過監測 Java 程式運作時,所有對象的申請、釋放等動作,将記憶體管理的所有資訊進行統計、分析、可視化。開發人員将根據這些資訊判斷程式是否有記憶體洩漏問題。這些工具包括 Optimizeit Profiler、JProbe Profiler、JinSight、Rational 公司的 Purify 等。
注意像 HashMap 、ArrayList 的集合對象
特别注意一些像 HashMap 、ArrayList 的集合對象,它們經常會引發記憶體洩漏。當它們被聲明為 static 時,它們的生命周期就會和應用程式一樣長。
注意 事件監聽 和 回調函數
特别注意 事件監聽 和 回調函數 。當一個監聽器在使用的時候被注冊,但不再使用之後卻未被反注冊。
總結:
綜上所述,Java也存在記憶體洩露問題,其原因主要是一些對象雖然不再被使用,但它們仍然被引用。為了解決這些問題,我們可以通過軟體工具來檢查記憶體洩露,檢查的主要原理就是暴露出所有堆中的對象,讓程式員尋找那些無用但仍被引用的對象。
---------------------