JAVA 垃圾處理

1. 什麼是內存垃圾,哪些內存符合垃圾的標準
我們在前面講過了,堆是一個"運行時"數據區,是通過"new"等指令建立的,Java 的堆
是由Java 的垃圾回收機制來負責處理的,堆是動態分配內存大小,垃圾收集器可以自動回
收不再使用的內存空間。
也就是說,所謂的"內存垃圾"是指在堆上開闢的內存空間在不用的時候就變成了"垃圾
"。
C++或其他程序設計語言中,必須由程序員自行聲明產生和回收,否則其中的資源將消
耗,造成資源的浪費甚至死機。但手工回收內存往往是一項複雜而艱鉅的工作。因爲要預先
確定佔用的內存空間是否應該被回收是非常困難的!如果一段程序不能回收內存空間,而且
在程序運行時系統中又沒有了可以分配的內存空間時,這段程序就只能崩潰。
Java 和C++相比的優勢在於,這部分"垃圾"可以被Java 虛擬機(JVM)中的一個程序
發現並自動清除掉,而不用程序員自己想着"delete"了。
Java 語言提供了一個系統級的線程,即垃圾收集器線程( Garbage Collection
Thread)
,來跟蹤每一塊分配出去的內存空間,當JVM 處於空閒循環時,自動回收每一塊可
以回收的內存。
1.1 垃圾回收工作機制
垃圾收集器線程它是一種低優先級的線程,它必須在一個Java 程序的運行過程中出現
內存空閒的時候纔去進行回收處理。
垃圾收集器系統有其判斷內存塊是否需要回收的判斷標準的。垃圾收集器完全是自動被
執行的,它不能被強制執行,即使程序員能明確地判斷出某一塊內存應該被回收了,也不能
強制執行垃圾回收程序進行垃圾回收。
程序員可以做的只有調用"System.gc()"來"建議"執行垃圾收集器程序,但是這個垃圾
收集程序什麼時候被執行以及是否被執行了,都是不不能控制的。但是雖然垃圾收集器是低
優先級的線程,卻在系統內存可用量過低時,它仍然可能會突發地執行來挽救系統。
1.2 哪些符合"垃圾"標準
如果想了解JVM 的垃圾回收,就必須要知道JVM 垃圾回收的標準。
垃圾收集器的"垃圾"標準:對象已經不能被程序中的其他程序所引用的時候,那麼這個
對象的內存空間已經沒有用了。
比如當一個方法執行完畢時,在這個方法中聲明的對象就超出其聲明週期,這時候就可
以被當作垃圾收集了,只有當這個方法被再次被調用時纔會被重新創建。
例如:
另外還可以將對象的引用變量初始化爲null 值,也可以來暗示垃圾收集器來收集該對
象。
例如:
1.3 finalize()在該對象垃圾回收前調用
垃圾收集器跟蹤每一個對象,把那些不可到達的對象佔有的內存空間收集起來,並且在
每次進行垃圾收集之前,垃圾收集器都會調用一下finalize()方法。Java 語言允許程序員
給任何對象添加finalize( )方法,但也不能過分依賴該方法對系統資源的回收和再利用,
因爲這個方法調用後的執行結果是不可預知的。對於任何給定對象,Java 虛擬機最多隻調
用一次finalize 方法。
我們用這個程序來演示一下:
……
public void function(){
OBJ obj=new OBJ();
……
}
……
……
OBJ obj=new OBJ();
Obj=null;
……
我們在命令行中鍵入如下命令:
這時候,我們將JVM 所許可使用的最大內存設置成"1k",當內存被佔滿前JVM 會首先去進行
public class finalizeTest{
public static void main( String[] args ){
finalizeTest ft=new finalizeTest();
ft.loading();
byte bs[]=new byte[1450000];
}
public void loading(){
test t=new test();
t.callme();
}
}
class test{
protected void finalize(){
System.out.println("call finalize");
}
public void callme(){
System.out.println("callme");
}
}
java -Xmx1k finalizeTest
內存回收,於是失去活動的"test"對象被回收,在回收前調用了"finalize()"。
2. JVM 垃圾回收的相關知識
JVM 使用的是分代垃圾回收的方式,主要是因爲在程序運行的時候會有如下特點:
大多數對象在創建後很快就沒有對象使用它了。
大多數在一直被使用的對象很少再去引用新創建的對象。
因此就將Java 對象分爲"年輕"對象和"年老"對象,JVM 將內存堆(Heap)分爲兩個區
域,一個是"年輕"區,另一個是"老"區,Java 將這兩個區域分別稱作是"新生代"和"老生代
"。
"新生代"區域中,絕大多數新創建的對象都存放在這個區域裏,此區域一般來說較小而
且垃圾回收頻率較高,同時因爲"新生代"採用的算法和其存放的對象的特點,使該區域垃圾
回收的效率也非常高。
而"老生代"區域中存放的是在"新生代"中生存了較長時間的對象,這些對象將被轉移到
"老生代"區。這個區域一般要大一些而且增長的速度相對於"新生代"要慢一些,"老生代"
垃圾回收的執行頻率也會低很多。
由於JVM 在垃圾回收處理時會消耗一定的系統資源,因此有時候通過JVM 啓動的時候添
加相關參數來控制"新生代"區域的大小,來調整垃圾回收處理的頻率非常有用。以便於我們
更合理的利用系統資源。
"新生代"區域設置參數是"-Xmn",用這個參數可以制定"新生代"區域的大小。
我們來舉一個例子說明:
我們就用系統自帶的程序作爲例子,在命令行上鍵入如下指令:
上面加入了一個新的參數"XX:+PrintGCDetails",這個參數能夠打印出GC 的詳細信息。屏
幕輸出如下(節選):
CD C:\java\demo\jfc\SwingSet2[回車]
C:\java\demo\jfc\SwingSet2>java -jar -verbose:gc
-Xmn4m XX:+PrintGCDetails SwingSet2.jar[回車]
我們需要解釋一下輸出的詳細內容的意思,拿第一行輸出來說:
"DefNew: 3469K->84K(3712K), 0.0007778 secs"是指"新生代"的垃圾回收情況,這裏
的意思是從佔用3469K 內存空間變爲84K 內存空間,用時0.0007778秒。
"23035K->19679K(28728K), 0.0009191 secs"是指總體GC 的回收情況,整體堆空間佔
用從23035K 降低到19679K 的水平,用時0.0009191秒。
那麼,這時候我們在將"新生代"的內存設爲8M,並把堆的最大可控值設定爲32M,再去
執行,鍵入如下指令:
得到的結果如下(節選):
這個結果說明:
[GC [DefNew: 3469K->84K(3712K), 0.0007778 secs]
23035K->19679K(28728K), 0.0009191 secs]
[GC [DefNew: 3284K->171K(3712K), 0.0007283 secs]
22878K->19766K(28728K), 0.0008669 secs]
[GC [DefNew: 3476K->260K(3712K), 0.0008504 secs]
23071K->19855K(28728K), 0.0009862 secs]
[GC [DefNew: 3502K->87K(3712K), 0.0009267 secs]
23096K->19682K(28728K), 0.0010610 secs]
java -jar -verbose:gc -Xmn8m -Xmx32m
XX:+PrintGCDetails SwingSet2.jar[回車]
[GC [DefNew: 6633K->6633K(7424K), 0.0000684 secs]
[Tenured: 18740K->18820K(24576K), 0.0636505 secs]
25374K->18820K(32000K), 0.0639274 secs]
[GC [DefNew: 6646K->6646K(7424K), 0.0002581 secs]
[Tenured: 18820K->18884K(24576K), 0.0651957 secs]
25467K->18884K(32000K), 0.0658804 secs]
[GC [DefNew: 6611K->6611K(7424K), 0.0000668 secs]
[Tenured: 18884K->18505K(24576K), 0.0931406 secs]
25496K->18505K(32000K), 0.0934295 secs]
"[DefNew: 6633K->6633K(7424K), 0.0000684 secs]"是指"新生代"的垃圾回收情況,
這裏的意思是從佔用6633K 內存空間變爲6633K 內存空間,用時0. 0000684秒。
"25374K->18820K(32000K), 0.0639274 secs"是指總體GC 的回收情況,整體堆空間佔用從
25374K 降低到18820K 的水平,用時0. 0639274秒。
"[Tenured: 18740K->18820K(24576K), 0.0636505 secs]"是指"老生代"GC 的回收情況,整
體堆空間佔用從18740K 降低到18820K 的水平,用時0.0009012秒。
通過這些參數的調整我們可以看到在處理垃圾收集問題時,從垃圾回收的頻率是時間方
面的變化,我們可以根據不同程序的不同情況予以調整。
最後有必要提一下GC 的相關參數:
-XX:+PrintGCDetails 顯示GC 的詳細信息
-XX:+PrintGCApplicationConcurrentTime 打印應用執行的時間
-XX:+PrintGCApplicationStoppedTime 打印應用被暫停的時間
注:":"後的"+"號表示開啓此選項,如果是"-"號那麼表示關閉此選項。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章