**所謂的新生代和老年代是針對於分代收集算法來定義的,新生代又分為Eden和Survivor兩個區。加上老年代就這三個區。數據會首先分配到Eden區 當中(當然也有特殊情況,如果是大對象那么會直接放入到老年代(大對象是指需要大量連續內存空間的java對象)。),當Eden沒有足夠空間的時候就會 觸發jvm發起一次Minor GC。如果對象經過一次Minor GC還存活,並且又能被Survivor空間接受,那么將被移動到Survivor空 間當中。並將其年齡設為1,對象在Survivor每熬過一次Minor GC,年齡就加1,當年齡達到一定的程度(默認為15)時,就會被晉升到老年代 中了,當然晉升老年代的年齡是可以設置的。
其實新生代和老年代就是針對於對象做分區存儲,更便於回收等等**
新生代主要存放的是哪些很快就會被GC回收掉的或者不是特別大的對象(這個大就要看你是否設置了-XX:PretenureSizeThreshold 參數了)。新生代采用的復制
算法,即將新生代分為3個區:較大的Eden和兩個較小的Survivor(默認的Eden:Survivor = 8:1)。發生在新生代的GC為Minor GC 。在Minor GC時會將新生代中
還存活着的對象復制進一個Survivor中,然后對Eden和另一個Survivor進行清理。所以,平常可用的新生代大小為Eden的大小+一個Survivor的大小。
年代則是存放那些在程序中經歷了好幾次回收仍然還活着或者特別大的對象(這個大就要看你是否設置了-XX:PretenureSizeThreshold 參數了)。老年代采用
的是標記-清除或者標記-整理算法,這兩個算法主要看虛擬機采用的哪個收集器,兩種算法的區別是:標記-清除可能會產生大量連續的內存碎片。在老年代中的GC
則為Major GC。Major GC和Full GC會造成stop-the-world。
-Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256m
Xms,即為jvm啟動時得JVM初始堆大小,Xmx為jvm的最大堆大小,xmn為新生代的大小,permsize為永久代的初始大小,MaxPermSize為永久代的最大空間。
老年代和新生代也是和內存相關,虛擬機初始化時已經設定了使用的內存大小,並划分為三部分:新生代– 新創建的對象,
舊生代 – 經過多次垃圾回收沒有被回收的對象或者大對象
持久代– JVM使用的內存,包含類信息等
**所謂的新生代和老年代是針對於分代收集算法來定義的,新生代又分為Eden和Survivor兩個區。加上老年代就這三個區。數據會首先分配到Eden區 當中(當然也
有特殊情況,如果是大對象那么會直接放入到老年代(大對象是指需要大量連續內存空間的java對象)。),當Eden沒有足夠空間的時候就會 觸發jvm發起一次
Minor GC。如果對象經過一次Minor GC還存活,並且又能被Survivor空間接受,那么將被移動到Survivor空 間當中。並將其年齡設為1,對象在Survivor每熬過一
次Minor GC,年齡就加1,當年齡達到一定的程度(默認為15)時,就會被晉升到老年代 中了,當然晉升老年代的年齡是可以設置的。
其實新生代和老年代就是針對於對象做分區存儲,更便於回收等等**
當對象在 Eden ( 包括一個 Survivor 區域,這里假設是 from 區域 ) 出生后,在經過一次 Minor GC 后,如果對象還存活,並且能夠被另外一塊 Survivor 區域所容納( 上面已經假設為 from 區域,這里應為 to 區域,即 to 區域有足夠的內存空間來存儲 Eden 和 from 區域中存活的對象 ),則使用復制算法將這些仍然還存活的對象復制到另外一塊 Survivor 區域 ( 即 to 區域 ) 中,然后清理所使用過的 Eden 以及 Survivor 區域 ( 即 from 區域 ),並且將這些對象的年齡設置為1,以后對象在 Survivor 區每熬過一次 Minor GC,就將對象的年齡 + 1,當對象的年齡達到某個值時 ( 默認是 15 歲,可以通過參數 -XX:MaxTenuringThreshold 來設定 ),這些對象就會成為老年代。 但這也不是一定的,對於一些較大的對象 ( 即需要分配一塊較大的連續內存空間 ) 則是直接進入到老年代;
Full GC 發生的次數不會有 Minor GC 那么頻繁,並且做一次 Full GC 要比進行一次 Minor GC 的時間更長;
因為 jvm 每次只是用新生代中的 eden 和 一個 survivor,因此新生代實際的可用內存空間大小為所指定的 90%;
PermGen 即永久代 ( 方法區 ),它還有一個名字,叫非堆,主要用來存儲由 jvm 加載的類文件信息、常量、靜態變量等;
每次調 System.gc(),是先進行 Minor GC,然后再進行 Full GC;
當 Full GC 進行的時候,默認的方式是盡量清空新生代 ( YoungGen ),因此在調 System.gc() 時,新生代 ( YoungGen ) 中存活的對象會提前進入老年代;
題眼:
JVM使用的是分代垃圾回收的方式,可以將Java對象分為"年輕"對象和"年老"對象.
JVM將內存堆(Heap)分為兩個區域,一個是"年輕"區,另一個是"老"區,Java將這兩個區域分別稱作是"新生代"和"老生代"。
詳細:
JVM使用的是分代垃圾回收的方式,主要是因為在程序運行的時候會有如下特點:
◆大多數對象在創建后很快就沒有對象使用它了。
◆大多數在一直被使用的對象很少再去引用新創建的對象。
因此就將Java對象分為"年輕"對象和"年老"對象,JVM將內存堆(Heap)分為兩個區域,
一個放年輕對象,一個放年老對象,java對對內存的這兩個區域分別成為 新生代,老生代。
新生代區域特點:
a) 絕大多數新創建的對象都存放在這個區域
b) 此區域一般來說較小而且JVM垃圾回收頻率較高
c) 采用的算法和存放對象特點使得該區域JVM垃圾回收的效率也非常高
老生代區域特點:
a) 將在"新生代"中生存了較長時間的對象轉移過來
b) 區域一般要大一些而且增長的速度相對於"新生代"要慢一些
c) 垃圾回收的執行頻率也會低很多
了解這個對於我們的好處是:
JVM在JVM垃圾回收處理時會消耗一定的系統資源,如果我們在JVM啟動的時候添加相關參數來控制"新生代"區域的大小
以達到調整JVM垃圾回收處理的頻率,那么我們就會合理利用系統資源。
操作新生代參數設置寫法:
-Xmn
操作案例如下:
我們就用系統自帶的程序作為例子,在命令行上鍵入如下指令:
Java代碼
CDC:\java\demo\jfc\SwingSet2[回車]C:\java\demo\jfc\SwingSet2>
java-jar-verbose:gc-Xmn4mXX:+PrintGCDetailsSwingSet2.jar[回車]
上面加入了一個新的參數"XX:+PrintGCDetails",這個參數能夠打印出GC的詳細信息。屏幕輸出如下(節選):
Java代碼
[GC[DefNew:3469K->84K(3712K),0.0007778secs]23035K->
19679K(28728K),0.0009191secs][GC[DefNew:3284K->
171K(3712K),0.0007283secs]22878K->
19766K(28728K),0.0008669secs][GC[DefNew:3476K->
260K(3712K),0.0008504secs]23071K->
19855K(28728K),0.0009862secs][GC[DefNew:3502K->
87K(3712K),0.0009267secs]23096K->
19682K(28728K),0.0010610secs]
我們需要解釋一下輸出的詳細內容的意思,拿第一行輸出來說:
Java代碼
"DefNew:3469K->84K(3712K),0.0007778secs"是指"新生代"的JVM垃圾回收情況,這里的意思是從占用3469K內存空間變為84K內存空間,用時0.0007778秒。
"23035K->19679K(28728K),0.0009191secs"是指總體GC的回收情況,整體堆空間占用從23035K降低到19679K的水平,用時0.0009191秒。
那么,這時候我們在將"新生代"的內存設為8M,並把堆的最大可控值設定為32M,再去執行,鍵入如下指令:
Java代碼
java-jar-verbose:gc-Xmn8m-Xmx32mXX:+PrintGCDetailsSwingSet2.jar[回車]
得到的結果如下(節選):
Java代碼
[GC[DefNew:6633K->6633K(7424K),0.0000684secs]
[Tenured:18740K->18820K(24576K),0.0636505secs]25374K->
18820K(32000K),0.0639274secs][GC[DefNew:6646K->
6646K(7424K),0.0002581secs][Tenured:18820K->
18884K(24576K),0.0651957secs]25467K->
18884K(32000K),0.0658804secs][GC[DefNew:6611K->
6611K(7424K),0.0000668secs][Tenured:18884K->
18505K(24576K),0.0931406secs]25496K->
18505K(32000K),0.0934295secs]
這個結果說明:
Java代碼
"[DefNew:6633K->6633K(7424K),0.0000684secs]"是指"新生代"的JVM垃圾回收情況,這里的意思是從占用6633K內存空間變為6633K內存空間,用時0.0000684秒。
"25374K->18820K(32000K),0.0639274secs"是指總體GC的回收情況,整體堆空間占用從25374K降低到18820K的水平,用時0.0639274秒。
"[Tenured:18740K->18820K(24576K),0.0636505secs]"是指"老生代"GC的回收情況,整體堆空間占用從18740K降低到18820K的水平,用時0.0009012秒。
通過這些參數的調整我們可以看到在處理垃圾收集問題時,從JVM垃圾回收的頻率是時間方面的變化,我們可以根據不同程序的不同情況予以調整。
最后有必要提一下GC的相關參數:
Java代碼
-XX:+PrintGCDetails顯示GC的詳細信息
-XX:+PrintGCApplicationConcurrentTime打印應用執行的時間
-XX:+PrintGCApplicationStoppedTime打印應用被暫停的時間
注:":"后的"+"號表示開啟此選項,如果是"-"號那么表示關閉此選項。
補充:
1 通過設置-xx:PretenureSizeThreshold 來設置多大的對象直接進入老年代。你把這個值調的大一點,則可以保證大部分對象不會直接進入老年代,老年代對象的gc同長慢,一般內存不滿時不會gc的,所以你的大對象一直都在不會被回收。
2 (-xx:MaxTenuringThreshold默認15)這個值也可以調調,這個表示在新生代折騰多少次后進入年老代。