Java 垃圾回收器學習

一 

引言:最近在看《Thinking in java》,不得不說號稱java四大名著的書籍,的確有倆把刷子,解決了很多我以前不理解的問題。樓主是一個菜鳥,寫這篇博客供以後學習,參考,若有不對的地方,請各位大牛指出。

先看一段代碼:
<span style="font-family:Microsoft YaHei;font-size:14px;">public void test(int i)
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>book b=new book();
<span style="white-space:pre">	</span>}</span>

大家先來看看這個方法,它是主類裏面的一個方法,book類是我自定義的一個類。我先拋出一個問題問下大家。主類每次調用test()方法,book對象會被反覆的創建嗎?? 再次之前樓主這樣理解的:book對象會被反覆的創建但是當b的作用域結束時對象book(),就會被清除內存。 事實究竟是這樣的嗎?  書上給出的解釋:當引用b在作用域終點就會消失。然而b指向的對象book依舊存在內存中。但是因爲垃圾回收器的存在。在內存中的book對象肯定不會很多,不會創建一個book,內存中就開闢了一片內存。

接下來我來介紹倆個方法這倆個方法是所有的類都具有的:finalize()和System.gc()
finalize()方法的作用:我根據書本的意思理解爲:標記。垃圾回收器在內存不夠的情況下才會回收垃圾,垃圾回收器假如當前正在回收A垃圾,當回收完了在回收B垃圾。垃圾回收器肯定不會說在回收完A之後,然後再根據一系列算法決定回收B,肯定在回收A垃圾過程中或者開始之前就已經知道下一個回收B。

所以我對finalize() 方法的理解就是標記,當某一個類調用了finalize()方法後,回收器並不馬上就來回收。 書上這樣解釋的:垃圾回收器在準備回收A對象內存前,將先調用其finalize(),當回收動作發生的時候纔會真正回收內存。

System.gc(),根據網上百度的結果:就是讓回收器來回收內存。就像現實生活中 你喊人家吃飯,人家肯能說馬上就來馬上就來,但具體什麼時候來卻不知道,唯一知道的是 他很快就來。System.gc(),方法類似一個督促的作用。通過這個小例子我想說明的是:System.gc()方法執行了後,回收器並不一定馬上來執行。

接下來看一個例子:
<pre name="code" class="java"><span style="font-family:Microsoft YaHei;font-size:14px;">public class book {
	public void start()
	{
		System.out.println("程序開始執行");
	}
	
	public void end()
	{
		System.out.println("程序執行結束");
	}
	
	@Override
	protected void finalize() throws Throwable {
		end();
		super.finalize();
	}</span>
<span style="font-family:Microsoft YaHei;font-size:14px;">}</span>


這是book 類。
<span style="font-family:Microsoft YaHei;font-size:14px;">public class Main {

	public static void main(String args[])
	{
		Main main=new Main();
		book b=new book();
		b.start();
		System.gc();
	}</span>

	
運行結果:



可以看到 沒有打印出 "程序執行結束"的標記。

既然執行了System.gc 爲什麼半天都沒執行finalize()方法呢。沒執行finilize()方法 說明當前的book沒有被回收。 不難看出  垃圾回收器 會主動回收 引用爲null 的對象。 在這裏我要提一個觀點:引用存放在 堆棧中,一切對象(new 生成的)都存在堆中。(堆和堆棧是java 數據存儲的位置,不懂的可以百度看下)
引用爲空的時候,引用對應的那個對象就會被Gc回收,當然確切時間肯定不清楚。


下面我們將上面的代碼稍微改下:

<pre name="code" class="java"><span style="font-family:Microsoft YaHei;font-size:14px;">public static void main(String args[])
	{
		Main main=new Main();
		book b=new book();
		b.start();
		b=null;//<span style="background-color: rgb(255, 255, 102);">注意此時引用b爲空了</span>
		System.gc();
	}</span>


運行結果如下:


這時候  “程序運行結束”,說明執行了 finalize()方法,但是具體什麼時候回收了這個對象呢。這個不清楚。


上述的demo:主要是講了一下 回收器的基礎知識,下面我們回到文章開頭,test方法被多次調用book 對象是否存在多個,或者說book是否new了多個。看下面代碼
<pre name="code" class="java"><span style="font-family:Microsoft YaHei;font-size:14px;">public class Main {

	public static void main(String args[])
	{
		Main main=new Main();
		
		for(int i=0;i<5;i++)
		{
			main.test();
		}
	}
	public void test()
	{
		book b=new book();
		b.start();
		System.gc();
	}</span>
<span style="font-family:Microsoft YaHei;font-size:14px;">}</span>

大家看下運行結果:


可以看到 有4個輸入“程序結束”  5個輸出“程序開始” ,這個結果說明倆個問題:

1.System.gc執行完畢 回收器可能不是立刻執行。
2.反覆的執行test方法,book對象會被反覆創建,但是 當引用b在作用域的終點時,回收器就會來回收垃圾,最終結果 只有一個對象存在於內存中。(當然假如這裏你把所有的 引用都保存在list集合中,我猜測 "程序執行結束" 一個都不會運行)

在這裏提下:引用b=null  和引用b的作用域消失 不是一個意思。在上述代碼b.start 後面加一個b=null  看下,“程序運行結束”會執行幾次,經樓主測試  執行了5次這說明 引用作用域消失和引用爲null,Gc執行的機制不同。

博客到這裏也就結束了。這些內容也是我看書,然後動手寫demo來驗證,並不是一定正確,這只是代表我的看法,有不同意見大可以提出。花了2,3個小時寫這個博客,希望能幫到一些人。樓主本身是一個菜鳥,但是我有一顆不斷進取的心,我堅信總有一天會成爲專家。借鴻洋大神的一句話:“生命不息,永垂不止”。











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