java內存管理深入淺出

        摘要:本文主要講解了Java中的內存管理機制、泄露機制及各種數據的存儲方式,內存管理是JAVA學習中的一個重點,深入理解它有助於幫助我們加深對JAVA程序的理解

1.java是如何管理內存的

      爲了判斷Java中是否有內存泄露,我們首先必須瞭解Java是如何管理內存的。Java的內存管理就是對象的分配和釋放問題。在Java中,內存的分配是由程序完成的,而內存的釋放是由垃圾收集器(Garbage Collection,GC)完成的,程序員不需要通過調用函數來釋放內存,但它只能回收無用並且不再被其它對象引用的那些對象所佔用的空間。

      Java的內存垃圾回收機制是從程序的主要運行對象開始檢查引用鏈,當遍歷一遍後發現沒有被引用的孤立對象就作爲垃圾回收。GC爲了能夠正確釋放對象,必須監控每一個對象的運行狀態,包括對象的申請、引用、被引用、賦值等,GC都需要進行監控。監視對象狀態是爲了更加準確地、及時地釋放對象,而釋放對象的根本原則就是該對象不再被引用。

        在Java中,這些無用的對象都由GC負責回收,因此程序員不需要考慮這部分的內存泄露。雖然,我們有幾個函數可以訪問GC,例如運行GC的函數System.gc(),但是根據Java語言規範定義,該函數不保證JVM的垃圾收集器一定會執行。因爲不同的JVM實現者可能使用不同的算法管理GC。通常GC的線程的優先級別較低。JVM調用GC的策略也有很多種,有的是內存使用到達一定程度時,GC纔開始工作,也有定時執行的,有的是平緩執行GC,有的是中斷式執行GC。但通常來說,我們不需要關心這些。 

      爲了更好理解GC的工作原理,我們可以將對象考慮爲有向圖的頂點,將引用關係考慮爲圖的有向邊,有向邊從引用者指向被引對象。另外,每個線程對象可以作爲一個圖的起始頂點,例如大多程序從main進程開始執行,那麼該圖就是以main進程頂點開始的一棵根樹。在這個有向圖中,根頂點可達的對象都是有效對象,GC將不回收這些對象。如果某個對象 (連通子圖)與這個根頂點不可達(注意,該圖爲有向圖),那麼我們認爲這個(這些)對象不再被引用,可以被GC回收。

以下,我們舉一個例子說明如何用有向圖表示內存管理。對於程序的每一個時刻,我們都有一個有向圖表示JVM的內存分配情況。以下右圖,就是左邊程序運行到第6行的示意圖。


Java使用有向圖的方式進行內存管理,可以消除引用循環的問題,例如有三個對象,相互引用,只要它們和根進程不可達的,那麼GC也是可以回收它們的。這種方式的優點是管理內存的精度很高,但是效率較低。另外一種常用的內存管理技術是使用計數器,例如COM模型採用計數器方式管理構件,它與有向圖相比,精度行低(很難處理循環引用的問題),但執行效率很高。


2.什麼叫java的內存泄露

        導致內存泄漏主要的原因是,先前申請了內存空間而忘記了釋放。如果程序中存在對無用對象的引用,那麼這些對象就會駐留內存,消耗內存,因爲無法讓垃圾回收器GC驗證這些對象是否不再需要。如果存在對象的引用,這個對象就被定義爲"有效的活動",同時不會被釋放。要確定對象所佔內存將被回收,我們就要務必確認該對象不再會被使用。典型的做法就是把對象數據成員設爲null或者從集合中移除該對象。但當局部變量不需要時,不需明顯的設爲null,因爲一個方法執行完畢時,這些引用會自動被清理。

        在Java中,內存泄漏就是存在一些被分配的對象,這些對象有下面兩個特點,首先,這些對象是有被引用的,即在有向樹形圖中,存在樹枝通路可以與其相連;其次,這些對象是無用的,即程序以後不會再使用這些對象。如果對象滿足這兩個條件,這些對象就可以判定爲Java中的內存泄漏,這些對象不會被GC所回收,然而它卻佔用內存。  

       下面,我們就可以描述什麼是內存泄漏。在Java中,內存泄漏就是存在一些被分配的對象,這些對象有下面兩個特點,首先,這些對象是可達的,即在有向圖中,存在通路可以與其相連;其次,這些對象是無用的,即程序以後不會再使用這些對象。如果對象滿足這兩個條件,這些對象就可以判定爲Java中的內存泄漏,這些對象不會被GC所回收,然而它卻佔用內存。

在C++中,內存泄漏的範圍更大一些。有些對象被分配了內存空間,然後卻不可達,由於C++中沒有GC,這些內存將永遠收不回來。在Java中,這些不可達的對象都由GC負責回收,因此程序員不需要考慮這部分的內存泄露。

通過分析,我們得知,對於C++,程序員需要自己管理邊和頂點,而對於Java程序員只需要管理邊就可以了(不需要管理頂點的釋放)。通過這種方式,Java提高了編程的效率。




        對於程序員來說,GC基本是透明的,不可見的。雖然,我們只有幾個函數可以訪問GC,例如運行GC的函數System.gc(),但是根據Java語言規範定義, 該函數不保證JVM的垃圾收集器一定會執行。因爲,不同的JVM實現者可能使用不同的算法管理GC。通常,GC的線程的優先級別較低。JVM調用GC的策略也有很多種,有的是內存使用到達一定程度時,GC纔開始工作,也有定時執行的,有的是平緩執行GC,有的是中斷式執行GC。但通常來說,我們不需要關心這些。除非在一些特定的場合,GC的執行影響應用程序的性能,例如對於基於Web的實時系統,如網絡遊戲等,用戶不希望GC突然中斷應用程序執行而進行垃圾回收,那麼我們需要調整GC的參數,讓GC能夠通過平緩的方式釋放內存,例如將垃圾回收分解爲一系列的小步驟執行,Sun提供的HotSpot JVM就支持這一特性。

     下面給出了一個簡單的內存泄露的例子。在這個例子中,我們循環申請Object對象,並將所申請的對象放入一個Vector中,如果我們僅僅釋放引用本身,那麼Vector仍然引用該對象,所以這個對象對GC來說是不可回收的。因此,如果對象加入到Vector後,還必須從Vector中刪除,最簡單的方法就是將Vector對象設置爲null。

Vector v=new Vector(10);
for (int i=1;i<100; i++)
{
	Object o=new Object();
	v.add(o);
	o=null;	
}

//此時,所有的Object對象都沒有被釋放,因爲變量v引用這些對象。

        再引用另一個例子來說明Java的內存泄漏。假設有一個日誌類Logger,其提供一個靜態的log(String msg),任何其它類都可以調用Logger.Log(message)來將message的內容記錄到系統的日誌文件中。        Logger類有一個類型爲HashMap的靜態變量temp,每次在執行log(message)的時候,都首先將message的值寫入temp中(以當前線程+當前時間爲鍵),在退出之前再從temp中將以當前線程和當前時間爲鍵的條目刪除。注意,這裏當前時間是不斷變化的,所以log在退出之前執行刪除條目的操作並不能刪除執行之初寫入的條目。這樣,任何一個作爲參數傳給log的字符串最終由於被Logger的靜態變量temp引用,而無法得到回收,這種對象保持就是我們所說的Java內存泄漏。 總的來說,內存管理中的內存泄漏產生的主要原因:保留下來卻永遠不再使用的對象引用。

3.JVM的內存區域組成

        程序運行時,我們最好對數據保存到什麼地方做到心中有數。特別要注意的是內存的分配。有六個地方都可以保存數據:
(1) 寄存器。這是最快的保存區域,因爲它位於和其他所有保存方式不同的地方:處理器內部。然而,寄存器的數量十分有限,所以寄存器是根據需要由編譯器分配。我們對此沒有直接的控制權,也不可能在自己的程序裏找到寄存器存在的任何蹤跡。
(2) 堆棧。駐留於常規RAM(隨機訪問存儲器)區域,但可通過它的“堆棧指針”獲得處理的直接支持。堆棧指針若向下移,會創建新的內存;若向上移,則會釋放那些內存。這是一種特別快、特別有效的數據保存方式,僅次於寄存器。創建程序時,Java編譯器必須準確地知道堆棧內保存的所有數據的“長度”以及“存在時間”。這是由於它必須生成相應的代碼,以便向上和向下移動指針。這一限制無疑影響了程序的靈活性,所以儘管有些Java數據要保存在堆棧裏——特別是對象句柄,但Java對象並不放到其中。
(3) 堆。一種常規用途的內存池(也在RAM區域),其中保存了Java對象。和堆棧不同,“內存堆”或“堆”(Heap)最吸引人的地方在於編譯器不必知道要從堆裏分配多少存儲空間,也不必知道存儲的數據要在堆裏停留多長的時間。因此,用堆保存數據時會得到更大的靈活性。要求創建一個對象時,只需用new命令編制相關的代碼即可。執行這些代碼時,會在堆裏自動進行數據的保存。當然,爲達到這種靈活性,必然會付出一定的代價:在堆裏分配存儲空間時會花掉更長的時間!
(4) 靜態存儲。這兒的“靜態”(Static)是指“位於固定位置”(儘管也在RAM裏)。程序運行期間,靜態存儲的數據將隨時等候調用。可用static關鍵字指出一個對象的特定元素是靜態的。但Java對象本身永遠都不會置入靜態存儲空間。
(5) 常數存儲。常數值通常直接置於程序代碼內部。這樣做是安全的,因爲它們永遠都不會改變。有的常數需要嚴格地保護,所以可考慮將它們置入只讀存儲器(ROM)。
(6) 非RAM存儲。若數據完全獨立於一個程序之外,則程序不運行時仍可存在,並在程序的控制範圍之外。其中兩個最主要的例子便是“流式對象”和“固定對象”。對於流式對象,對象會變成字節流,通常會發給另一臺機器。而對於固定對象,對象保存在磁盤中。即使程序中止運行,它們仍可保持自己的狀態不變。對於這些類型的數據存儲,一個特別有用的技巧就是它們能存在於其他媒體中。一旦需要,甚至能將它們恢復成普通的、基於RAM的對象。Java 1.1提供了對Lightweight persistence的支持。未來的版本甚至可能提供更完整的方案。

4.java中數據在內存中是如何存儲的

a)基本數據類型

java的基本數據類型共有8種,即int,short,long,byte,float,double,boolean,char(注意,並沒有String的基本類型 )。這種類型的定義是通過諸如int a = 3;long b = 255L;的形式來定義的。如int a = 3;這裏的a是一個指向int類型的引用,指向3這個字面值。這些字面值的數據,由於大小可知,生存期可知(這些字面值定義在某個程序塊裏面,程序塊退出後,字段值就消失了),出於追求速度的原因,就存在於棧中。

另外,棧有一個很重要的特殊性,就是存在棧中的數據可以共享。比如:
我們同時定義:(注意,這裏指在同一函數中定義的基本類型變量

int a=3;
int b=3;

編譯器先處理int a = 3;首先它會在棧中創建一個變量爲a的引用,然後查找有沒有字面值爲3的地址,沒找到,就開闢一個存放3這個字面值的地址,然後將a指向3的地址。接着處理int b = 3;在創建完b這個引用變量後,由於在棧中已經有3這個字面值,便將b直接指向3的地址。這樣,就出現了a與b同時均指向3的情況。

定義完a與b的值後,再令a = 4;那麼,b不會等於4,還是等於3。在編譯器內部,遇到時,它就會重新搜索棧中是否有4的字面值,如果沒有,重新開闢地址存放4的值;如果已經有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值。

b)對象

在java中,創建一個對象包括對象的聲明和實例化兩步,下面用一個例題來說明對象的內存模型。假設有類Rectangle定義如下:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public class Rectangle {  
  2. double width;  
  3. double height;  
  4. public Rectangle( double w, double h){  
  5. w = width;  
  6. h = height;  
  7. }  
  8. }  

c)創建多個不同的對象實例

一個類通過使用new運算符可以創建多個不同的對象實例,這些對象實例將在堆中被分配不同的內存空間,改變其中一個對象的狀態不會影響其他對象的狀態。例如:

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">Rectangle</span><span class="pln" style="color: rgb(72, 72, 76);"> r1</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Rectangle</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="lit" style="color: rgb(25, 95, 145);">3</span><span class="pun" style="color: rgb(147, 161, 161);">,</span><span class="lit" style="color: rgb(25, 95, 145);">5</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">Rectangle</span><span class="pln" style="color: rgb(72, 72, 76);"> r2</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Rectangle</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="lit" style="color: rgb(25, 95, 145);">4</span><span class="pun" style="color: rgb(147, 161, 161);">,</span><span class="lit" style="color: rgb(25, 95, 145);">6</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li></ol>

此時,將在堆內存中分別爲兩個對象的成員變量 width 、 height 分配內存空間,兩個對象在堆內存中佔據的空間是互不相同的。如果有:

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">Rectangle</span><span class="pln" style="color: rgb(72, 72, 76);"> r1</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Rectangle</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="lit" style="color: rgb(25, 95, 145);">3</span><span class="pun" style="color: rgb(147, 161, 161);">,</span><span class="lit" style="color: rgb(25, 95, 145);">5</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">Rectangle</span><span class="pln" style="color: rgb(72, 72, 76);"> r2</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);">r1</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li></ol>

則在堆內存中只創建了一個對象實例,在棧內存中創建了兩個對象引用,兩個對象引用同時指向一個對象實例。

d)包裝類

基本類型都有對應的包裝類:如int對應Integer類,double對應Double類等,基本類型的定義都是直接在棧中,如果用包裝類來創建對象,就和普通對象一樣了。例如:int i=0;i直接存儲在棧中。Integer i(i此時是對象)= new Integer(5);這樣,i對象數據存儲在堆中,i的引用存儲在棧中,通過棧中的引用來操作對象。

e)String

String是一個特殊的包裝類數據。可以用以下兩種方式創建:String str = new String(“abc”);String str = “abc”;
第一種創建方式,和普通對象的的創建過程一樣;
第二種創建方式,java內部將此語句轉化爲以下幾個步驟:
(1)先定義一個名爲str的對String類的對象引用變量:String str;
(2)在棧中查找有沒有存放值爲”abc”的地址,如果沒有,則開闢一個存放字面值爲”abc”
地址,接着創建一個新的String類的對象o,並將o的字符串值指向這個地址,而且在棧
這個地址旁邊記下這個引用的對象o。如果已經有了值爲”abc”的地址,則查找對象o,並
回o的地址。
(3)將str指向對象o的地址。
值得注意的是,一般String類中字符串值都是直接存值的。但像String str = “abc”;這種
合下,其字符串值卻是保存了一個指向存在棧中數據的引用。
爲了更好地說明這個問題,我們可以通過以下的幾個代碼進行驗證。

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">String</span><span class="pln" style="color: rgb(72, 72, 76);"> str1</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="str" style="color: rgb(221, 17, 68);">"abc"</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">String</span><span class="pln" style="color: rgb(72, 72, 76);"> str2</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="str" style="color: rgb(221, 17, 68);">"abc"</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">System</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="kwd" style="color: rgb(30, 52, 123);">out</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);">println</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="pln" style="color: rgb(72, 72, 76);">s1</span><span class="pun" style="color: rgb(147, 161, 161);">==</span><span class="pln" style="color: rgb(72, 72, 76);">s2</span><span class="pun" style="color: rgb(147, 161, 161);">);</span><span class="com" style="color: rgb(147, 161, 161);">//true</span></li></ol>

注意,這裏並不用 str1.equals(str2);的方式,因爲這將比較兩個字符串的值是否相等。==號,根據JDK的說明,只有在兩個引用都指向了同一個對象時才返回真值。而我們在這裏要看的是,str1與str2是否都指向了同一個對象。
我們再接着看以下的代碼。

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">String</span><span class="pln" style="color: rgb(72, 72, 76);"> str1</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">String</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"abc"</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">String</span><span class="pln" style="color: rgb(72, 72, 76);"> str2</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="str" style="color: rgb(221, 17, 68);">"abc"</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">System</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="kwd" style="color: rgb(30, 52, 123);">out</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);">println</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="pln" style="color: rgb(72, 72, 76);">str1</span><span class="pun" style="color: rgb(147, 161, 161);">==</span><span class="pln" style="color: rgb(72, 72, 76);">str2</span><span class="pun" style="color: rgb(147, 161, 161);">);</span><span class="com" style="color: rgb(147, 161, 161);">//false</span></li></ol>

創建了兩個引用。創建了兩個對象。兩個引用分別指向不同的兩個對象。
以上兩段代碼說明,只要是用new()來新建對象的,都會在堆中創建,而且其字符串是單獨存值的,即使與棧中的數據相同,也不會與棧中的數據共享。

f)數組

當定義一個數組,int x[];或int[] x;時,在棧內存中創建一個數組引用,通過該引用(即數組名)來引用數組。x=new int[3];將在堆內存中分配3個保存 int型數據的空間,堆內存的首地址放到棧內存中,每個數組元素被初始化爲0。

g)靜態變量

用static的修飾的變量和方法,實際上是指定了這些變量和方法在內存中的”固定位置”-static storage,可以理解爲所有實例對象共有的內存空間。static變量有點類似於C中的全局變量的概念;靜態表示的是內存的共享,就是它的每一個實例都指向同一個內存地址。把static拿來,就是告訴JVM它是靜態的,它的引用(含間接引用)都是指向同一個位置,在那個地方,你把它改了,它就不會變成原樣,你把它清理了,它就不會回來了。

那靜態變量與方法是在什麼時候初始化的呢?對於兩種不同的類屬性,static屬性與instance屬性,初始化的時機是不同的。instance屬性在創建實例的時候初始化,static屬性在類加載,也就是第一次用到這個類的時候初始化,對於後來的實例的創建,不再次進行初始化。

我們常可看到類似以下的例子來說明這個問題:

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">class</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Student</span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">static</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">int</span><span class="pln" style="color: rgb(72, 72, 76);"> numberOfStudents </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="lit" style="color: rgb(25, 95, 145);">0</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">Student</span><span class="pun" style="color: rgb(147, 161, 161);">()</span></li><li class="L3" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L4" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">numberOfStudents </span><span class="pun" style="color: rgb(147, 161, 161);">++;</span></li><li class="L5" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li><li class="L6" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li></ol>

每一次創建一個新的Student實例時,成員numberOfStudents都會不斷的遞增,並且所有的Student實例都訪問同一個numberOfStudents變量,實際上intnumberOfStudents變量在內存中只存儲在一個位置上。

5.java的內存管理實例

Java程序的多個部分(方法,變量,對象)駐留在內存中以下兩個位置:即堆和棧,現在我們只關心三類事物:實例變量,局部變量和對象:
實例變量和對象駐留在堆上
局部變量駐留在棧上
讓我們查看一個 java 程序,看看他的各部分如何創建並且映射到棧和堆中:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public class Dog {  
  2. Collar c;  
  3. String name;  
  4. //1.main()方法位於棧上  
  5. public static void main(String[] args) {  
  6. //2.在棧上創建引用變量d,但Dog對象尚未存在  
  7. Dog d;  
  8. //3.創建新的Dog對象,並將其賦予d引用變量  
  9. d = new Dog();  
  10. //4.將引用變量的一個副本傳遞給go()方法  
  11. d.go(d);  
  12. }  
  13. //5.將go()方法置於棧上,並將dog參數作爲局部變量  
  14. void go(Dog dog){  
  15. //6.在堆上創建新的Collar對象,並將其賦予Dog的實例變量  
  16. c = new Collar();  
  17. }  
  18. //7.將setName()添加到棧上,並將dogName參數作爲其局部變量  
  19. void setName(String dogName){  
  20. //8.name的實例對象也引用String對象  
  21. name =dogName;  
  22. }  
  23. //9.程序執行完成後,setName()將會完成並從棧中清除,此時,局部變量dogName也會消失,儘管它所引用的String仍在堆上  
  24. }  

6. 垃圾回收機制

問題一:什麼叫垃圾回收機制?
垃圾回收是一種動態存儲管理技術,它自動地釋放不再被程序引用的對象,按照特定的垃圾收集算法來實現資源自動回收的功能。當一個對象不再被引用的時候,內存回收它佔領的空間,以便空間被後來的新對象使用,以免造成內存泄露。

問題二:java的垃圾回收有什麼特點?
jAVA語言不允許程序員直接控制內存空間的使用。內存空間的分配和回收都是由JRE負責在後臺自動進行的,尤其是無用內存空間的回收操作(garbagecollection,也稱垃圾回收),只能由運行環境提供的一個超級線程進行監測和控制。

問題三:垃圾回收器什麼時候會運行?
一般是在CPU空閒或空間不足時自動進行垃圾回收,而程序員無法精確控制垃圾回收的時機和順序等。、

問題四:什麼樣的對象符合垃圾回收條件?
當沒有任何獲得線程能訪問一個對象時,該對象就符合垃圾回收條件。

問題五:垃圾回收器是怎樣工作的?
垃圾回收器如發現一個對象不能被任何活線程訪問時,他將認爲該對象符合刪除條件,就將其加入回收隊列,但不是立即銷燬對象,何時銷燬並釋放內存是無法預知的。垃圾回收不能強制執行,然而java提供了一些方法(如:System.gc()方法),允許你請求JVM執行垃圾回收,而不是要求,虛擬機會盡其所能滿足請求,但是不能保證JVM從內存中刪除所有不用的對象。

問題六:一個java程序能夠耗盡內存嗎?
可以。垃圾收集系統嘗試在對象不被使用時把他們從內存中刪除。然而,如果保持太多活的對象,系統則可能會耗盡內存。垃圾回收器不能保證有足夠的內存,只能保證可用內存儘可能的得到高效的管理。

問題七:如何顯示的使對象符合垃圾回收條件?
(1)空引用:當對象沒有對他可到達引用時,他就符合垃圾回收的條件。也就是說如果沒有對他的引用,刪除對象的引用就可以達到目的,因此我們可以把引用變量設置爲null,來符合垃圾回收的條件。

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">StringBuffer</span><span class="pln" style="color: rgb(72, 72, 76);"> sb </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"hello"</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">System</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="kwd" style="color: rgb(30, 52, 123);">out</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);">println</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="pln" style="color: rgb(72, 72, 76);">sb</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">sb</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">null</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li></ol>
(2)重新爲引用變量賦值:可以通過設置引用變量引用另一個對象來解除該引用變量與一個對象間的引用關係。
StringBuffer sb1 = new StringBuffer(“hello”);
StringBuffer sb2 = new StringBuffer(“goodbye”);
System.out.println(sb1);
sb1=sb2;//此時”hello”符合回收條件
(3)方法內創建的對象:所創建的局部變量僅在該方法的作用期間內存在。一旦該方法返回,在這個方法內創建的對象就符合垃圾收集條件。有一種明顯的例外情況,就是方法的返回對象。

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">public</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">static</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">void</span><span class="pln" style="color: rgb(72, 72, 76);"> main</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="typ" style="color: teal;">String</span><span class="pun" style="color: rgb(147, 161, 161);">[]</span><span class="pln" style="color: rgb(72, 72, 76);"> args</span><span class="pun" style="color: rgb(147, 161, 161);">)</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">Date</span><span class="pln" style="color: rgb(72, 72, 76);"> d </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> getDate</span><span class="pun" style="color: rgb(147, 161, 161);">();</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">System</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="kwd" style="color: rgb(30, 52, 123);">out</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);">println</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"d="</span><span class="pun" style="color: rgb(147, 161, 161);">+</span><span class="pln" style="color: rgb(72, 72, 76);">d</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L3" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li><li class="L4" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">private</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">static</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Date</span><span class="pln" style="color: rgb(72, 72, 76);"> getDate</span><span class="pun" style="color: rgb(147, 161, 161);">()</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L5" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">Date</span><span class="pln" style="color: rgb(72, 72, 76);"> d2 </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Date</span><span class="pun" style="color: rgb(147, 161, 161);">();</span></li><li class="L6" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">StringBuffer</span><span class="pln" style="color: rgb(72, 72, 76);"> now </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="pln" style="color: rgb(72, 72, 76);">d2</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);">toString</span><span class="pun" style="color: rgb(147, 161, 161);">());</span></li><li class="L7" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">System</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="kwd" style="color: rgb(30, 52, 123);">out</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);">println</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="pln" style="color: rgb(72, 72, 76);">now</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L8" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">return</span><span class="pln" style="color: rgb(72, 72, 76);"> d2</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L9" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li></ol>
(4)隔離引用:這種情況中,被回收的對象仍具有引用,這種情況稱作隔離島。若存在這兩個實例,他們互相引用,並且這兩個對象的所有其他引用都刪除,其他任何線程無法訪問這兩個對象中的任意一個。也可以符合垃圾回收條件。

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">public</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">class</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Island</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">Island</span><span class="pln" style="color: rgb(72, 72, 76);"> i</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">public</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">static</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">void</span><span class="pln" style="color: rgb(72, 72, 76);"> main</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="typ" style="color: teal;">String</span><span class="pun" style="color: rgb(147, 161, 161);">[]</span><span class="pln" style="color: rgb(72, 72, 76);"> args</span><span class="pun" style="color: rgb(147, 161, 161);">)</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L3" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">Island</span><span class="pln" style="color: rgb(72, 72, 76);"> i2 </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Island</span><span class="pun" style="color: rgb(147, 161, 161);">();</span></li><li class="L4" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">Island</span><span class="pln" style="color: rgb(72, 72, 76);"> i3 </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Island</span><span class="pun" style="color: rgb(147, 161, 161);">();</span></li><li class="L5" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">Island</span><span class="pln" style="color: rgb(72, 72, 76);"> i4 </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Island</span><span class="pun" style="color: rgb(147, 161, 161);">();</span></li><li class="L6" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">i2</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);"> i </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);">i3</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L7" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">i3</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);"> i </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);">i4</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L8" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">i4</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);"> i </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);">i2</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L9" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">i2</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">null</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">i3</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">null</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">i4</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">null</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li><li class="L3" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li></ol>

7.final問題

final使得被修飾的變量”不變”,但是由於對象型變量的本質是”引用”,使得”不變”也有了兩種含義:引用本身的不變和引用指向的對象不變。
引用本身的不變:

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">final</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pln" style="color: rgb(72, 72, 76);"> a</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"immutable"</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">final</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pln" style="color: rgb(72, 72, 76);"> b</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"not immutable"</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">a</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);">b</span><span class="pun" style="color: rgb(147, 161, 161);">;</span><span class="com" style="color: rgb(147, 161, 161);">//編譯期錯誤</span></li><li class="L3" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">final</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pln" style="color: rgb(72, 72, 76);"> a</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"immutable"</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L4" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">final</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pln" style="color: rgb(72, 72, 76);"> b</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"not immutable"</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li></ol>

a=b;//編譯期錯誤

引用指向的對象不變:

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">final</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pln" style="color: rgb(72, 72, 76);"> a</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"immutable"</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">a</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);">append</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"broken!"</span><span class="pun" style="color: rgb(147, 161, 161);">);</span><span class="com" style="color: rgb(147, 161, 161);">//編譯通過</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">final</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pln" style="color: rgb(72, 72, 76);"> a</span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">StringBuffer</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"immutable"</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L3" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">a</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);">append</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"broken!"</span><span class="pun" style="color: rgb(147, 161, 161);">);</span><span class="com" style="color: rgb(147, 161, 161);">//編譯通過</span></li></ol>

可見,final只對引用的”值”(也即它所指向的那個對象的內存地址)有效,它迫使引用只能指向初始指向的那個對象,改變它的指向會導致編譯期錯誤。至於它所指向的對象的變化,final是不負責的。這很類似==操作符:==操作符只負責引用的”值”相等,至於這個地址所指向的對象內容是否相等,==操作符是不管的。在舉一個例子:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. class Name{  
  2.     private String firstname;  
  3.     private String lastname;  
  4.     public String getFirstname() {  
  5.         return firstname;  
  6.     }  
  7.     public void setFirstname(String firstname) {  
  8.         this.firstname = firstname;  
  9.     }  
  10.     public String getLastname() {  
  11.         return lastname;  
  12.     }  
  13.     public void setLastname(String lastname) {  
  14.         this.lastname = lastname;  
  15.     }  
  16.       
  17. }  
  18. public class learning1 {  
  19.   
  20.     public static void main(String[] args) {  
  21.     final Name name=new Name();  
  22.     name.setFirstname("lin");  
  23.     name.setLastname("bingwen");  
  24.     System.out.println("firstname:"+name.getFirstname()+" lastname:"+name.getLastname());  
  25.     name.setFirstname("evan");  
  26.     name.setLastname("kaka");  
  27.     System.out.println("firstname:"+name.getFirstname()+" lastname:"+name.getLastname());  
  28.     }  
  29.   
  30. }  
結果:

firstname:lin lastname:bingwen
firstname:evan lastname:kaka

       理解final問題有很重要的含義。許多程序漏洞都基於此—-final只能保證引用永遠指向固定對象,不能保證那個對象的狀態不變。在多線程的操作中,一個對象會被多個線程共享或修改,一個線程對對象無意識的修改可能會導致另一個使用此對象的線程崩潰。一個錯誤的解決方法就是在此對象新建的時候把它聲明爲final,意圖使得它”永遠不變”。其實那是徒勞的.final還有一個值得注意的地方,
先看以下示例程序:

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">class</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Something</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">final</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">int</span><span class="pln" style="color: rgb(72, 72, 76);"> i </span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">public</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">void</span><span class="pln" style="color: rgb(72, 72, 76);"> doSomething</span><span class="pun" style="color: rgb(147, 161, 161);">()</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L3" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">System</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">out</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);">println</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="str" style="color: rgb(221, 17, 68);">"i = "</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">+</span><span class="pln" style="color: rgb(72, 72, 76);"> i </span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L4" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li><li class="L5" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li><li class="L6" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">class</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Something</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L7" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">final</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">int</span><span class="pln" style="color: rgb(72, 72, 76);"> i</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L8" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">public</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">void</span><span class="pln" style="color: rgb(72, 72, 76);"> doSomething</span><span class="pun" style="color: rgb(147, 161, 161);">()</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L9" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">System</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="kwd" style="color: rgb(30, 52, 123);">out</span><span class="pun" style="color: rgb(147, 161, 161);">.</span><span class="pln" style="color: rgb(72, 72, 76);">println</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"i = "</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">+</span><span class="pln" style="color: rgb(72, 72, 76);"> i</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li></ol>

對於類變量,java虛擬機會自動進行初始化。如果給出了初始值,則初始化爲該初始值。如果沒有給出,則把它初始化爲該類型變量的默認初始值。但是對於用final修飾的類變量,虛擬機不會爲其賦予初值,必須在constructor(構造器)結束之前被賦予一個明確的值。可以修改爲”final int i = 0;”。

8.如何把程序寫得更健壯

(1)儘早釋放無用對象的引用。
好的辦法是使用臨時變量的時候,讓引用變量在退出活動域後,自動設置爲null,暗示垃圾收集器來收集該對象,防止發生內存泄露。對於仍然有指針指向的實例,jvm就不會回收該資源,因爲垃圾回收會將值爲null的對象作爲垃圾,提高GC回收機制效率;

(2)定義字符串應該儘量使用String str=”hello”;的形式,避免使用String str = new String(“hello”);的形式。因爲要使用內容相同的字符串,不必每次都new一個String。例如我們要在構造器中對一個名叫s的String引用變量進行初始化,把它設置爲初始值,應當這樣做:

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">public</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">class</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Demo</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">private</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">String</span><span class="pln" style="color: rgb(72, 72, 76);"> s</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">public</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Demo</span><span class="pun" style="color: rgb(147, 161, 161);">()</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L3" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">s </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="str" style="color: rgb(221, 17, 68);">"Initial Value"</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L4" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li><li class="L5" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li><li class="L6" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);"> </span></li><li class="L7" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">public</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">class</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Demo</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L8" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">private</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">String</span><span class="pln" style="color: rgb(72, 72, 76);"> s</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L9" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">...</span></li><li class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="kwd" style="color: rgb(30, 52, 123);">public</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">Demo</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="pun" style="color: rgb(147, 161, 161);">{</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">s </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="str" style="color: rgb(221, 17, 68);">"Initial Value"</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li><li class="L3" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">...</span></li><li class="L4" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">}</span></li><li class="L5" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pun" style="color: rgb(147, 161, 161);">而非</span></li><li class="L6" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">s </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);">  </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);">  </span><span class="typ" style="color: teal;">String</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"Initial Value"</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li><li class="L7" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">s </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="kwd" style="color: rgb(30, 52, 123);">new</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="typ" style="color: teal;">String</span><span class="pun" style="color: rgb(147, 161, 161);">(</span><span class="str" style="color: rgb(221, 17, 68);">"Initial Value"</span><span class="pun" style="color: rgb(147, 161, 161);">);</span></li></ol>

後者每次都會調用構造器,生成新對象,性能低下且內存開銷大,並且沒有意義,因爲String對象不可改變,所以對於內容相同的字符串,只要一個String對象來表示就可以了。也就說,多次調用上面的構造器創建多個對象,他們的String類型屬性s都指向同一個對象。

(3)我們的程序裏不可避免大量使用字符串處理,避免使用String,應大量使用StringBuffer,因爲String被設計成不可變(immutable)類,所以它的所有對象都是不可變對象,請看下列代碼;

<ol class="linenums" style="padding: 0px; margin: 0px 0px 0px 38px; list-style-position: initial;"><li value="1" class="L0" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">String</span><span class="pln" style="color: rgb(72, 72, 76);"> s </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="str" style="color: rgb(221, 17, 68);">"Hello"</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L1" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">s </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> s </span><span class="pun" style="color: rgb(147, 161, 161);">+</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="str" style="color: rgb(221, 17, 68);">" world!"</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L2" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; color: rgb(190, 190, 197); line-height: 18px;"><span class="typ" style="color: teal;">String</span><span class="pln" style="color: rgb(72, 72, 76);"> s </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="str" style="color: rgb(221, 17, 68);">"Hello"</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li><li class="L3" style="padding: 0px 0px 0px 3px; margin: 0px; list-style: decimal; background-color: rgb(239, 239, 239); color: rgb(190, 190, 197); line-height: 18px;"><span class="pln" style="color: rgb(72, 72, 76);">s </span><span class="pun" style="color: rgb(147, 161, 161);">=</span><span class="pln" style="color: rgb(72, 72, 76);"> s </span><span class="pun" style="color: rgb(147, 161, 161);">+</span><span class="pln" style="color: rgb(72, 72, 76);"> </span><span class="str" style="color: rgb(221, 17, 68);">" world!"</span><span class="pun" style="color: rgb(147, 161, 161);">;</span></li></ol>

在這段代碼中,s原先指向一個String對象,內容是”Hello”,然後我們對s進行了+操作,那麼s所指向的那個對象是否發生了改變呢?答案是沒有。這時,s不指向原來那個對象了,而指向了另一個String對象,內容爲”Hello world!”,原來那個對象還存在於內存之中,只是s這個引用變量不再指向它了。

通過上面的說明,我們很容易導出另一個結論,如果經常對字符串進行各種各樣的修改,或者說,不可預見的修改,那麼使用String來代表字符串的話會引起很大的內存開銷。因爲String對象建立之後不能再改變,所以對於每一個不同的字符串,都需要一個String對象來表示。這時,應該考慮使用StringBuffer類,它允許修改,而不是每個不同的字符串都要生成一個新的對象。並且,這兩種類的對象轉換十分容易。

(4)儘量少用靜態變量,因爲靜態變量是全局的,GC不會回收的;

(5)儘量避免在類的構造函數裏創建、初始化大量的對象,防止在調用其自身類的構造器時造成不必要的內存資源浪費,尤其是大對象,JVM會突然需要大量內存,這時必然會觸發GC優化系統內存環境;顯示的聲明數組空間,而且申請數量還極大。
以下是初始化不同類型的對象需要消耗的時間:

運算操作

示例

標準化時間

本地賦值

i = n

1.0

實例賦值

this.i = n

1.2

方法調用

Funct()

5.9

新建對象

New Object()

980

新建數組

New int[10]

3100

從表中可以看出,新建一個對象需要980個單位的時間,是本地賦值時間的980倍,是方法調用時間的166倍,而新建一個數組所花費的時間就更多了。

(6)儘量在合適的場景下使用對象池技術以提高系統性能,縮減縮減開銷,但是要注意對象池的尺寸不宜過大,及時清除無效對象釋放內存資源,綜合考慮應用運行環境的內存資源限制,避免過高估計運行環境所提供內存資源的數量。

(7)大集合對象擁有大數據量的業務對象的時候,可以考慮分塊進行處理,然後解決一塊釋放一塊的策略。

(8)不要在經常調用的方法中創建對象,尤其是忌諱在循環中創建對象。可以適當的使用hashtable,vector創建一組對象容器,然後從容器中去取那些對象,而不用每次new之後又丟棄。

(9)一般都是發生在開啓大型文件或跟數據庫一次拿了太多的數據,造成Out Of Memory Error的狀況,這時就大概要計算一下數據量的最大值是多少,並且設定所需最小及最大的內存空間值。

(10)儘量少用finalize函數,因爲finalize()會加大GC的工作量,而GC相當於耗費系統的計算能力。

(11)不要過濫使用哈希表,有一定開發經驗的開發人員經常會使用hash表(hash表在JDK中的一個實現就是HashMap)來緩存一些數據,從而提高系統的運行速度。比如使用HashMap緩存一些物料信息、人員信息等基礎資料,這在提高系統速度的同時也加大了系統的內存佔用,特別是當緩存的資料比較多的時候。其實我們可以使用操作系統中的緩存的概念來解決這個問題,也就是給被緩存的分配一個一定大小的緩存容器,按照一定的算法淘汰不需要繼續緩存的對象,這樣一方面會因爲進行了對象緩存而提高了系統的運行效率,同時由於緩存容器不是無限制擴大,從而也減少了系統的內存佔用。現在有很多開源的緩存實現項目,比如ehcache、oscache等,這些項目都實現了FIFO 、MRU等常見的緩存算法。

轉載出處http://blog.csdn.net/evankaka

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