Java清理:finalize

簡述:

相信每個(gè)C程序員都知道銷毀對象的重要性,也熟悉析構(gòu)函數(shù)蚂会,但是java程序員可能就不太會(huì)關(guān)注銷毀對象计济。因?yàn)閖ava有垃圾回收器負(fù)責(zé)回收無用對象占據(jù)的內(nèi)存資源。當(dāng)然也有特殊情況:假定你的對象(并非使用new)獲得了一塊“特殊”的內(nèi)存區(qū)域嵌器,由于垃圾回收器只知道釋放那些由new分配的內(nèi)存,所以它不知道該如何釋放這塊“特殊內(nèi)存”谐丢。

為了應(yīng)對這個(gè)特殊的情況爽航,java允許在類中定義一個(gè)名為finalize()的方法。它的工作原理“假定”是這樣的:一旦垃圾回收器準(zhǔn)備好釋放對象占用的存儲(chǔ)空間庇谆,將首先調(diào)用其finalize()方法岳掐。并且在下一次垃圾回收動(dòng)作發(fā)生時(shí),才會(huì)真正回收對象占用的內(nèi)存饭耳。所以要是你打算用finalize(),就能在垃圾回收時(shí)刻做一些重要的清理工作串述。

這里有一潛在的編程陷阱,因?yàn)橛行┏绦騿T(特別是C++程序員)剛開始可能會(huì)把finalize()當(dāng)做C++中的析構(gòu)函數(shù)寞肖。所有有必要明確區(qū)分一下纲酗。在C++中如果程序沒有缺陷的話,那么對象一定會(huì)被銷毀新蟆。而java的對象卻并非總是被垃圾回收觅赊,或者換句話說:

1.對象可能不被垃圾回收。
2.垃圾回收并不等于“析構(gòu)”琼稻。

因?yàn)槔厥毡旧硪矔?huì)有開銷吮螺,如果不使用它,那么就不會(huì)支付這部分開銷帕翻。所以當(dāng)程序沒有瀕臨存儲(chǔ)空間用完的那一刻鸠补,對象占用的空間就總也得不到釋放。如果程序執(zhí)行結(jié)束嘀掸,并且垃圾回收器一直都沒有釋放你創(chuàng)建的任何對象的存儲(chǔ)空間紫岩,則隨著程序的退出,那些資源也會(huì)全部交還給操作系統(tǒng)睬塌。所以這里的第三點(diǎn):

3.垃圾回收只與內(nèi)存有關(guān)

finalize()的用途何在:

使用垃圾回收器的唯一原因是為了回收程序不再使用的內(nèi)存泉蝌。所以對于與垃圾回收有關(guān)的任何行為來說(尤其是finalize方法),它們也必須同內(nèi)存及其回收有關(guān)揩晴。
但是并不意味之對象中含有其他對象勋陪,finalize()就應(yīng)該明確釋放那些對象。無論對象是如何創(chuàng)建文狱,垃圾回收器都會(huì)負(fù)責(zé)釋放對象占據(jù)的所有內(nèi)存粥鞋。這就將對finalize()的需求先知道一種特殊情況,即通過某種創(chuàng)建對象方式為對象分配了存儲(chǔ)空間瞄崇。而這種方式非java中通常的做法呻粹。這種情況主要發(fā)生在使用“本地方法”的情況下,本地方法是一種在java中調(diào)用非java代碼的方式苏研。本地方法目前只支持C和C++等浊,但他們可以調(diào)用其他語言寫的代碼,所以實(shí)際上可以調(diào)用任何代碼摹蘑。在非java代碼中筹燕,也許會(huì)調(diào)用C的malloc()函數(shù)系列來分配存儲(chǔ)空間,而且出分調(diào)用了free()函數(shù)衅鹿,否則存儲(chǔ)空間將得不到釋放撒踪,從而造成內(nèi)存泄漏。當(dāng)然大渤,free()是C和C++中的函數(shù)制妄,所以需要在finalize()中用本地方法調(diào)用它。所以要有finalize()泵三。

必須要實(shí)施清理

要清理一個(gè)對象耕捞,用戶必須需要清理的時(shí)刻調(diào)用執(zhí)行清理動(dòng)作的方法。這聽起來似乎很簡單烫幕。在C++中創(chuàng)建了一個(gè)局部對象(也就是在堆棧中俺抽,這在java中是行不通的),應(yīng)該被銷毀较曼,但是程序員忘記調(diào)用delete()函數(shù)磷斧,那么永遠(yuǎn)不會(huì)調(diào)用析構(gòu)函數(shù),這樣就會(huì)出現(xiàn)內(nèi)存泄露捷犹,對象的其他部分也不會(huì)得到清理弛饭。這種缺陷很難跟蹤。
相反伏恐,java不允許創(chuàng)建局部對象孩哑, 必須使用new創(chuàng)建對象。在java中翠桦,也沒有用于釋放對象的delete横蜒,因?yàn)槔厥掌鲿?huì)幫助你釋放存儲(chǔ)空間。甚至可以膚淺的認(rèn)為销凑,正是由于垃圾收集機(jī)制的存在丛晌,使得java沒有析構(gòu)函數(shù)。然而斗幼,垃圾回收器的存在并不能完全代替析構(gòu)函數(shù)澎蛛。(而且絕對不能直接調(diào)用finalize(),因?yàn)閒inalize方法是Object類的一個(gè)Protected方法蜕窿。Protected方法只能被子類內(nèi)部調(diào)用谋逻,外部不能直接調(diào)用 呆馁,所以這也不是一種解決方案。)如果希望進(jìn)行除釋放存儲(chǔ)空間之外的清理工作毁兆,還是得明確調(diào)用某個(gè)恰當(dāng)?shù)姆椒ㄕ懵恕_@就等同于使用析構(gòu)函數(shù)了,只是乜有它方便气堕。
無論是“垃圾回收”還是“終結(jié)”纺腊,都不保證一定會(huì)發(fā)生。如果java虛擬機(jī)并未面臨內(nèi)存消耗的情形茎芭,他是不會(huì)浪費(fèi)時(shí)間去執(zhí)行垃圾回收以恢復(fù)內(nèi)存的揖膜。

class Book {
    boolean checkedOut = false;

    public Book(boolean checkOut) {
        // TODO Auto-generated constructor stub
        checkedOut = checkOut;
    }

    void checkIn() {
        checkedOut = false;
    }

    protected void finalize() {
        if (checkedOut) {
            System.out.println("Error: checked out");
        }
        //Nomally,you'll also do this梅桩。
        //super.finalize();
    }
}

public class TestFinalize {
    public static void main(String[] args) {
        Book novel = new Book(true);
        novel.checkIn();
        new Book(true);
        System.gc();
    }
}

本例的終結(jié)條件是:所有Book對象再被當(dāng)做垃圾回收錢都應(yīng)該被簽入(check in)壹粟。但是mian()方法中,由于程序員的錯(cuò)誤摘投,有一本書未被簽入煮寡。如果沒有finalize()來驗(yàn)證終結(jié)條件,將很難發(fā)現(xiàn)這種缺陷犀呼。
注意幸撕,System.gc()用于強(qiáng)制進(jìn)行終結(jié)動(dòng)作。即使不這么做外臂,通過重復(fù)地執(zhí)行程序(假設(shè)程序?qū)⒎峙浯罅康拇鎯?chǔ)空間而導(dǎo)致垃圾回收動(dòng)作的執(zhí)行)坐儿,最終也能找出錯(cuò)誤的Book對象。
你應(yīng)該總是假設(shè)基類版本的finalize()也要做某些重要的事情宋光,因此要使用super來調(diào)用它貌矿,就像在Book.finalize()中看到的那樣。在本例中罪佳,它被注釋掉了逛漫,因?yàn)樗枰M(jìn)行異常處理。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赘艳,一起剝皮案震驚了整個(gè)濱河市酌毡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蕾管,老刑警劉巖枷踏,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異掰曾,居然都是意外死亡旭蠕,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掏熬,“玉大人佑稠,你說我怎么就攤上這事∧踅” “怎么了讶坯?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵番电,是天一觀的道長岗屏。 經(jīng)常有香客問我,道長漱办,這世上最難降的妖魔是什么这刷? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮娩井,結(jié)果婚禮上暇屋,老公的妹妹穿的比我還像新娘。我一直安慰自己洞辣,他們只是感情好咐刨,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著扬霜,像睡著了一般定鸟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上著瓶,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天联予,我揣著相機(jī)與錄音,去河邊找鬼材原。 笑死沸久,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的余蟹。 我是一名探鬼主播卷胯,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼威酒!你這毒婦竟也來了窑睁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤兼搏,失蹤者是張志新(化名)和其女友劉穎卵慰,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體佛呻,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡裳朋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鲤嫡。...
    茶點(diǎn)故事閱讀 40,861評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡送挑,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出暖眼,到底是詐尸還是另有隱情惕耕,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布诫肠,位于F島的核電站司澎,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏栋豫。R本人自食惡果不足惜挤安,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望丧鸯。 院中可真熱鬧蛤铜,春花似錦、人聲如沸丛肢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蜂怎。三九已至穆刻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間派敷,已是汗流浹背蛹批。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留篮愉,地道東北人腐芍。 一個(gè)月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像试躏,于是被迫代替她去往敵國和親猪勇。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容