java內(nèi)存回收問題

首先看一下下面兩段代碼有什么區(qū)別:

{
    new A().test();
} 

{
    A a = new A();
    a.test();
}

當(dāng)時去問我們項目經(jīng)理,他堅持認(rèn)為這兩種方式是一樣的崭孤,個人習(xí)慣不同造成的不同寫法而已糊肠。就功能上來說,都調(diào)用了test()函數(shù)货裹,確實沒什么區(qū)別弧圆,但是笔咽,如果考慮了內(nèi)存回收叶组,這兩種寫法就有很大的不同扶叉。
我們可以把這個例子更具體一點帕膜,如下:

{
    //mark 1
    new A().test();
    //mark 2
    new A().test();
    //mark 3
    .....
}

第一種寫法垮刹,在mark2處荒典,A的內(nèi)存已經(jīng)可以被交給垃圾回收器回收了,也就是說在mark2處覆糟,可用內(nèi)存和mark1處的可用內(nèi)存完全相同遮咖。

{
    //mark 1
    A a = new A();
    //mark 2
    A b = new A();

    a.test();
    b.test();
}

第二種寫法在mark 2處的可用內(nèi)存和mark1處的可用內(nèi)存是不同的,如果A類使用很大的空間麦箍,那么在mark2這里會拋出內(nèi)存溢出異常陶珠,相反揍诽,第一種寫法卻沒有這種問題暑脆。
下面的測試代碼證明了兩種寫法的區(qū)別

class MemoryTest
{
 int a[] = new int[10 * 1024 * 1024 * 10];
 static int b = 0;
 
 MemoryTest()
 {
  b++;
  a[0] = a[1] = 2;
 }
 
 void Test()
 {
  System.out.println("12345 + " + b); 
 }
}

public class TestJava
{
 public static void main(String[] args)
 throws Exception
 {
  //works well
  new MemoryTest().Test();
  
  //the gc collected the memory so it can be reuse
  new MemoryTest().Test();
  
  MemoryTest c = new MemoryTest();
  
  //if cancel this comment, there will be a memory exception
  //that means there's not enough memory for d
  /*MemoryTest d = new MemoryTest();*/
  
  System.out.println("end test");
 }
}

造成這種問題饵筑,主要還是java的內(nèi)存回收機(jī)制根资,當(dāng)java發(fā)現(xiàn)可用內(nèi)存不足時,會調(diào)用內(nèi)存回收器部脚,內(nèi)存回收器會去遍歷當(dāng)前線程棧委刘,然后根據(jù)棧中的引用確定當(dāng)前被使用的內(nèi)存鹰椒,將沒有被遍歷到的內(nèi)存釋放,在上面的例子中淆珊,b處于棧上施符,無法被回收戳吝,因此在c申請新內(nèi)存是異常听哭。b和c指向的內(nèi)存要等到出了作用域(最近的大括號)才可以被回收柬采。
這個問題解決后,馬上又有一個新的問題粉捻,第一種寫法中我們調(diào)用 new A().test(); 如果這個函數(shù)執(zhí)行時間非常長礁遣,如何保證在執(zhí)行過程中A的內(nèi)存不會被回收(沒有顯式處于棧上的引用指向)。
考慮到c++的臨時變量肩刃,所以猜想java的編譯器會將new A().test();這段代碼做如下處理:

{
   {
        //mark 1
        A temp = new A();
        temp.test();
   }
   //mark 2
}

在mark1處祟霍,從棧上分配temp引用指向堆中的A,之后盈包,在mark2處沸呐,由于temp離開他自己的作用域,則棧上內(nèi)存釋放呢燥,也就是說棧上不再具有指向A的引用崭添,使得A內(nèi)存可被回收。

結(jié)論
推薦使用 new A().test();這樣的寫法叛氨,在一定程度上可以節(jié)省當(dāng)前內(nèi)存呼渣。
(原文時間2013-1-30)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末棘伴,一起剝皮案震驚了整個濱河市屁置,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌揪阶,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姐直,死亡現(xiàn)場離奇詭異,居然都是意外死亡愿棋,警方通過查閱死者的電腦和手機(jī)徘跪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門逗抑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人腐宋,你說我怎么就攤上這事〖灞” “怎么了马篮?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵迁央,是天一觀的道長。 經(jīng)常有香客問我募强,道長逐抑,這世上最難降的妖魔是什么汹粤? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上互捌,老公的妹妹穿的比我還像新娘钉疫。我一直安慰自己城菊,他們只是感情好漏麦,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布秧均。 她就那樣靜靜地躺著,像睡著了一般锯七。 火紅的嫁衣襯著肌膚如雪眉尸。 梳的紋絲不亂的頭發(fā)上巫延,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天疼阔,我揣著相機(jī)與錄音淘邻,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛猜扮,可吹牛的內(nèi)容都是我干的源譬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼孕似,長吁一口氣:“原來是場噩夢啊……” “哼踩娘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起喉祭,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤养渴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后泛烙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體理卑,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年蔽氨,在試婚紗的時候發(fā)現(xiàn)自己被綠了藐唠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鹉究,死狀恐怖宇立,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情自赔,我是刑警寧澤妈嘹,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站绍妨,受9級特大地震影響润脸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜痘绎,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一津函、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧孤页,春花似錦尔苦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蛾号,卻和暖如春稠项,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鲜结。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工展运, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留活逆,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓拗胜,卻偏偏與公主長得像蔗候,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子埂软,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

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