java之內存泄漏

     內存泄漏的問題也是老生常談的問題。C++由於內存的分配和回收都是由程序員自己管理的,coding的時候小心些,出現內存泄漏的機率就會很小。而java由於使用了GC,由GC自動去回收無用的內存,內存的管理似乎變得很簡單。但是,如果不知道GC的工作原理,一旦出現內存泄漏的問題,就十分頭痛了;即使知道了GC的工作原理,解決內存泄漏也是一件繁瑣的工作。當然,瞭解GC的基本工作原理,對解決內存泄漏的問題自然是隻有好處沒有壞處。本文並不是介紹GC的工作原理,而是筆者在實際工作中解決內存泄漏問題的一點心得,希望對大家會有所幫助。

     市面上有許多中jvm的實現,每種jvm幾乎都有自己的GC算法。但不管GC的算法如何,它的工作目的只有一個,就是要回收內存中不再使用的對象,釋放內存。通常,GC會去檢查內存中那些不再被引用的對象,然後標記這些對象,最後銷燬這些對象。由於GC是由一個專門的線程來運行的,回收對象的時候也很消耗資源,所以,我們一般不知道什麼時候GC會去回收內存。但這不是重點,重點是我們必須知道什麼樣的對象纔是GC認爲可以回收的對象,也就是說,什麼對象纔算是“不再被引用的對象”。關於這一點,網上的參考文獻往往會指出,GC從“root”即根節點開始查找,只要能從這個“root”節點到達的對象,都是可用的對象,換句話說,如果一個對象的引用者是在以“root”爲根的樹上,這個對象就是可用的,那麼,只要使這個對象脫離這棵樹,即令對象的在那棵樹上的引用者referrer=null,那麼這個對象就可被回收。但很少有文獻指出,這個“root”到底是什麼?哪些節點一定會在“root”這棵樹上?如果我們清楚了這個“root”的實際含義,問題就會迎刃而解了。

    其實這些“root”並不複雜。簡單起見,就拿一個應用程序爲例。假設一個應用程序有一個主線程,多個副線程。每個線程都會有一個入口,也就是每個線程都有一個主類,即含有pulic void main(String[] args)和pubic void run()的類,這個類中的字段,方法就是可能的“root”所在。只要一個線程在運行,主類中的字段,靜態或者非靜態的,就是“root”,同樣,如果一個方法在運行,比如run()是個無限循環,這個方法中的變量,也成爲了“root”。只要能從這些“root”出發,達到某個對象,這個對象就是無法被回收的。因此,簡而言之,我們可以把“root”理解爲一個線程。

    理解了這一點,解決內存泄漏的問題就不難了。“工欲善其事,必先利其器”。出現了內存泄漏,如果靠查看源碼,那是事倍功半的法子。有一個好的工具來幫助我們查找問題的根源,那就事半功倍。java中關於內存調試的工具也蠻多的,borland公司的optimizer,bea公司jrockit中自帶的一款工具等等。quest公司的JProbe也是很好的一個工具,關於這個工具介紹的網上資料也有一些,就不在贅述了。

         以下是Bea的關於內存泄漏的文章,有一定的參考價值:

         原文:

    http://dev2dev.bea.com/pub/a/2005/06/memory_leaks.html

   中文地址:
   http://www.matrix.org.cn/resource/article/43/43639_Memory_Leaks.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章