程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 關於垃圾回收的一些知識

關於垃圾回收的一些知識

編輯:關於JAVA

為什麼要進行垃圾回收?

因為JVM本身就實現內存堆裡的,它不可能有象C++的自動變量(臨時變量),所以所有的對象都要被會收.我們先來看一下C++:

ClassType varname;//自動變量,在內存的棧中創建,隨作用域的消失而自動消失.

ClassType varname = new ClassType();//在內存堆中創建,要程序員手工釋放,如:

delete varname;相當於C中的free

由於JVM本身就是在內存堆中實現,所以它不可能創建自動變量,所有的對象都有手工釋放,這個\\"手工"是指要程序實現,並不一定非要程序員編程,JVM自己就實現了"常規\\"對象的釋放,這就是JVM的垃圾回收器.

但對於非"常規\\"的對象比如直接或間接調用本地資源.(有人把圖象擦除認為不是本地方法調用,其實它只是AWT在間接調用本地方法而已),就是程序員自己編程來釋放資源.

一個對象是如何被標記垃圾(可回收對象)?以前有些實現采用"引用計數",就是一個對象在被引用的時候,引用計數加1,當引用句柄消失時引用計數減速1,當引用計數為0,就可被回收了.

那有人說剛new的對象不也被回收了嗎?

一個對象的生存期分為新生代,舊生代,新生代又分為Eden 和兩片生存空間其中保證有一片空間在任何時間是空的,對象剛被new的時候在Eden 中,垃圾回收器不會對Eden中對象回收,只有Eden中對象滿的時候,被復制到下一片生存空間.當生存空間滿的時候,才會發生一次小回收.當對象在生存空間太久達到一個\\"老化"的值時就被復制到了舊生代,舊生代滿的時候就發生大回收了.

但java並不是采用引用計數來標記一個對象是否可以回收的.因為Java中對象很可能被直接或間接循環引用,就是對象A中引用到對象B的一個屬性,而對象B又引用了A中一個屬性,這樣可能造成引用記數永遠不會為0.

Java中是采用"由根遍歷\\"來標記對象,就是從句柄開始對一個句柄引用的對象進行查找,然後對這個對象引用的對象再進行查找,這樣遞歸好象從樹根往沿枝條找到葉子,如果一個對象沒有被這樣查找到說明它已經沒有對象對它引用了.

如何釋放非JAVA對象?我們已經說過常規的Java對象會被JVM的垃圾回收器來回收,但對於本地資源(一般來說本地方法大都調用了本地資源),就要我們手工釋放了.

一般來說我們可以在finalize() 中定義釋放本地資源的代碼,但是這個方法不是肯定會被執行的,finalize() 不是在對象退出的時候運行,而是在對象被作為垃圾回收時才調用.有可能JVM一直不需要回收,所以這個方法就一直不會被調用,同樣如果要求對象在退出前一定要稍許對象,你一定要把釋放對象的代碼寫在try{}finally{}的finally塊中,這就是我再三強調釋放數據數連結一定要寫在這兒的原因,在Java1.1中還有個方法是System.runFinalizersOnExit(),但它不如finally來得更有效.

同樣System.gc()方法並不能保證垃圾回收的發生,它只是"建議\\",而垃圾回到到底什麼時候發生?小回收是生存空間滿,大回收是舊生代滿,這只是前提.因為垃圾回收是低優先級的方式運行,只有當其他線程都掛起等待內存釋放的情況出現時,它才開始釋放對象的內存.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved