首先Java虛擬機中gc的原理,能夠參見
http://www.360doc.com/content/12/1023/16/9615799_243296263.shtml
http://ifeve.com/useful-jvm-flags-part-5-young-generation-garbage-collection/
如下是一些我的總結和測試。 html
劃分新生代和老年代,這樣只在新生代分配內存,從而簡化了新對象的分配。另外新生代和老年代使用不一樣的GC算法,能夠更有效的清除再也不須要的對象。
從上圖能夠看出,JVM內存由young+old+permanent組成,JVM又進一步將Young分紅了eden,from survivor和to survivor三個區域。新對象會首先分配在 Eden 中(若是新對象過大,會直接分配在老年代中)。在GC中,Eden 中的對象會被移動到survivor中,直至對象熬過必定的GC的次數,會被移動到老年代。老年代通常是一些系統級(線程庫,classloader等) 的對象,官方推薦新生代佔堆大小的3/8,而survivor區各佔新生代的1/10。 java
不少對象的生存時間都很短,而新生對象不多引用生存時間長的對象。因此,GC會頻繁訪問新生代對象,執行Minor GC。在新生代中,GC能夠快速標記回收」死對象」,而不須要掃描整個Heap中的存活一段時間的」老對象」(即執行major/FULL GC)。
新生代的GC使用複製算法。在GC前To survivor區保持清空,對象保存在Eden和From survivor區中,GC運行時,Eden中的倖存對象被複制到 To survivor區。針對 From survivor取中的倖存對象,會考慮對象年齡,若是年齡沒達到閥值(tenuring threshold),對象會被複制到To survivor區。若是達到閥值對象被複制到老年代。複製階段完成後,Eden 和From survivor區中只保存死對象,能夠被視爲所有清空。若是在複製過程當中To survivor區被填滿了,剩餘的對象會被複制到老年代中。最後 From和To會對換。
上圖演示GC過程,黃色表示死對象,綠色表示剩餘空間,紅色表示倖存對象
若是新生代太小,會致使新生對象很快就晉升到老年代中,在老年代中對象很難被回收。若是新生代過大,會發生過多的複製過程。因此須要經過不斷的測試調優,找到一個合適的JVM參數。 算法
-Xms:初始堆大小。只要啓動,就佔用的堆大小
-Xmx:最大堆大小。java.lang.OutOfMemoryError: Java heap這個錯誤能夠經過配置-Xms和-Xmx參數來設置
-Xss:棧大小分配。棧是每一個線程私有的區域,一般只有幾百K大小,決定了函數調用的深度,而局部變量、參數都分配到棧上。當出現大量局部變量,遞歸時,會發生棧空間OOM(java.lang.StackOverflowError)之類的錯誤。
-XX:NewSize=n:設置新生代大小的絕對值
-XX:NewRatio=n: 設置年輕代和年老代的比值。好比設置爲3,則新生代:老年代=1:3,新生代佔1/4的總heap大小。
-XX:SurvivorRatio=n:年輕代中Eden區與兩個Survivor區的比值。注意Survivor區有from和to兩個。好比設置爲8時,那麼eden:from:to=8:1:1
-XX:MaxPermSize=n:設置持久代大小 ;java.lang.OutOfMemoryError: PermGen space這個OOM錯誤須要合理調大PermSize和MaxPermSize大小。
-XX:HeapDumpOnOutOfMemoryError:發生OOM時轉儲堆到文件,這是一個很是好的診斷方法。
-XX:HeapDumpPath:導出堆的轉儲文件路徑
-XX:OnOutOfMemoryError:OOM時,執行一個腳本,好比發送郵件報警,重啓程序。後面跟着一個腳本的路徑。 jvm
第一次分配5M,沒有超過xms。第二次再次分配5M,total mem會增長。第三次再申請40M,超過xmx限制因此報了OOM錯誤。 函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
public
class
JVMTest
{
public
static
void
main
(
String
args
[
]
)
{
//=====================Begin=========================
System
.
out
.
print
(
"Xmx="
)
;
System
.
out
.
println
(
Runtime
.
getRuntime
(
)
.
maxMemory
(
)
/
1024.0
/
1024
+
"M"
)
;
System
.
out
.
print
(
"free mem="
)
;
System
.
out
.
println
(
Runtime
.
getRuntime
(
)
.
freeMemory
(
)
/
1024.0
/
1024
+
"M"
)
;
System
.
out
.
print
(
"total mem="
)
;
System
.
out
.
println
(
Runtime
.
getRuntime
(
)
.
totalMemory
(
)
/
1024.0
/
1024
+
"M"
)
;
//=====================First Allocated=========================
System
.
out
.
println
(
"5MB array allocated"
)
;
byte
[
]
b1
=
new
byte
[
5
*
1024
*
1024
]
;
System
.
out
.
print
(
"Xmx="
)
;
System
.
out
.
println
(
Runtime
.
getRuntime
(
)
.
maxMemory
(
)
/
1024.0
/
1024
+
"M"
)
;
System
.
out
.
print
(
"free mem="
)
;
System
.
out
.
println
(
Runtime
.
getRuntime
(
)
.
freeMemory
(
)
/
1024.0
/
1024
+
"M"
)
;
System
.
out
.
print
(
"total mem="
)
;
System
.
out
.
println
(
Runtime
.
getRuntime
(
)
.
totalMemory
(
)
/
1024.0
/
1024
+
"M"
)
;
//=====================Second Allocated=========================
System
.
out
.
println
(
"10MB array allocated"
)
;
byte
[
]
b2
=
new
byte
[
10
*
1024
*
1024
]
;
System
.
out
.
print
(
"Xmx="
)
;
System
.
out
.
println
(
Runtime
.
getRuntime
(
)
.
maxMemory
(
)
/
1024.0
/
1024
+
"M"
)
;
System
.
out
.
print
(
"free mem="
)
;
System
.
out
.
println
(
Runtime
.
getRuntime
(
)
.
freeMemory
(
)
/
1024.0
/
1024
+
"M"
)
;
System
.
out
.
print
(
"total mem="
)
;
System
.
out
.
println
(
Runtime
.
getRuntime
(
)
.
totalMemory
(
)
/
1024.0
/
1024
+
"M"
)
;
//=====================OOM=========================
System
.
out
.
println
(
"OOM!!!"
)
;
System
.
gc
(
)
;
byte
[
]
b3
=
new
byte
[
40
*
1024
*
1024
]
;
}
}
|
以50m XMX和10m XMS的運行測試: 測試
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
D
:
\
>
java
-
Xmx50m
-
Xms10m
JVMTest
Xmx
=
44.5M
free
mem
=
9.804550170898438M
total
mem
=
10.5M
5MB
array
allocated
Xmx
=
44.5M
free
mem
=
4.804534912109375M
total
mem
=
10.5M
10MB
array
allocated
Xmx
=
44.5M
free
mem
=
5.3045196533203125M
total
mem
=
21.0M
OOM
!
!
!
Exception
in
thread
"main"
java
.
lang
.
OutOfMemoryError
:
Java
heap
space
at
JVMTest
.
main
(
JVMTest
.
java
:
43
)
|
1
2
3
4
5
6
7
|
public
class
JVMXmn1
{
public
static
void
main
(
String
args
[
]
)
{
byte
[
]
b
=
null
;
for
(
int
i
=
0
;
i
<
10
;
i
++
)
b
=
new
byte
[
1
*
1024
*
1024
]
;
}
}
|
下面按1m的新生代設置,這時對象大於新生代大小,會直接建立在老年代。新生代沒有使用。沒有觸發gc 優化
1
2
3
4
5
6
7
8
9
10
|
D
:
\
>
java
-
Xmx20m
-
Xms20m
-
Xmn1m
-
XX
:
+
PrintGCDetails
JVMXmn1
Heap
PSYoungGen
total
512K
,
used
0K
[
0x00000000fff00000
,
0x0000000100000000
,
0x0000000100000000
)
eden
space
0K
,
-
2147483648
%
used
[
0x00000000fff00000
,
0x00000000fff00000
,
0x00000000fff00000
)
from
space
512K
,
0
%
used
[
0x00000000fff80000
,
0x00000000fff80000
,
0x0000000100000000
)
to
space
512K
,
0
%
used
[
0x00000000fff00000
,
0x00000000fff00000
,
0x00000000fff80000
)
ParOldGen
total
19456K
,
used
10836K
[
0x00000000fec00000
,
0x00000000fff00000
,
0x00000000fff00000
)
object
space
19456K
,
55
%
used
[
0x00000000fec00000
,
0x00000000ff695348
,
0x00000000fff00000
)
PSPermGen
total
21504K
,
used
2442K
[
0x00000000f9a00000
,
0x00000000faf00000
,
0x00000000fec00000
)
object
space
21504K
,
11
%
used
[
0x00000000f9a00000
,
0x00000000f9c628d8
,
0x00000000faf00000
)
|
下面按15m的新生代設置,所有分配在eden區,老年代沒有使用,沒有觸發gc。 spa
1
2
3
4
5
6
7
8
9
10
|
D
:
\
>
java
-
Xmx20m
-
Xms20m
-
Xmn15m
-
XX
:
+
PrintGCDetails
JVMXmn1
Heap
PSYoungGen
total
13824K
,
used
11525K
[
0x00000000ff100000
,
0x0000000100000000
,
0x0000000100000000
)
eden
space
12288K
,
93
%
used
[
0x00000000ff100000
,
0x00000000ffc417c8
,
0x00000000ffd00000
)
from
space
1536K
,
0
%
used
[
0x00000000ffe80000
,
0x00000000ffe80000
,
0x0000000100000000
)
to
space
1536K
,
0
%
used
[
0x00000000ffd00000
,
0x00000000ffd00000
,
0x00000000ffe80000
)
ParOldGen
total
5120K
,
used
0K
[
0x00000000fea00000
,
0x00000000fef00000
,
0x00000000ff100000
)
object
space
5120K
,
0
%
used
[
0x00000000fea00000
,
0x00000000fea00000
,
0x00000000fef00000
)
PSPermGen
total
21504K
,
used
2442K
[
0x00000000f9800000
,
0x00000000fad00000
,
0x00000000fea00000
)
object
space
21504K
,
11
%
used
[
0x00000000f9800000
,
0x00000000f9a628d8
,
0x00000000fad00000
)
|
下面按8m的新生代設置,觸發了一次gc,因爲from和to的大小小於1M的對象大小,eden區會直接進入老年代。 線程
1
2
3
4
5
6
7
8
9
10
11
|
D
:
\
>
java
-
Xmx20m
-
Xms20m
-
Xmn8m
-
XX
:
+
PrintGCDetails
JVMXmn1
[
GC
[
PSYoungGen
:
5954K
->
536K
(
7168K
)
]
5954K
->
1560K
(
19456K
)
,
0.0021655
secs
]
[
Times
:
user
=
0.00
sys
=
0.00
,
real
=
0.00
secs
]
Heap
PSYoungGen
total
7168K
,
used
5971K
[
0x00000000ff800000
,
0x0000000100000000
,
0x0000000100000000
)
eden
space
6144K
,
88
%
used
[
0x00000000ff800000
,
0x00000000ffd4ecb8
,
0x00000000ffe00000
)
from
space
1024K
,
52
%
used
[
0x00000000ffe00000
,
0x00000000ffe86010
,
0x00000000fff00000
)
to
space
1024K
,
0
%
used
[
0x00000000fff00000
,
0x00000000fff00000
,
0x0000000100000000
)
ParOldGen
total
12288K
,
used
1024K
[
0x00000000fec00000
,
0x00000000ff800000
,
0x00000000ff800000
)
object
space
12288K
,
8
%
used
[
0x00000000fec00000
,
0x00000000fed00010
,
0x00000000ff800000
)
PSPermGen
total
21504K
,
used
2445K
[
0x00000000f9a00000
,
0x00000000faf00000
,
0x00000000fec00000
)
object
space
21504K
,
11
%
used
[
0x00000000f9a00000
,
0x00000000f9c63400
,
0x00000000faf00000
)
|
下面按7m的新生代設置,from和to的大小能夠爲1/xmn,大於觸發了3次新生代gc,一共回收了7M左右的空間,最後剩餘3M在系統當中,沒有使用老年代。 debug
1
2
3
4
5
6
7
8
9
10
11
12
13
|
D
:
\
>
java
-
Xmx20m
-
Xms20m
-
Xmn7m
-
XX
:
SurvivorRatio
=
2
-
XX
:
+
PrintGCDetails
JVMXmn1
[
GC
[
PSYoungGen
:
3785K
->
1512K
(
5632K
)
]
3785K
->
1568K
(
18944K
)
,
0.0024118
secs
]
[
Times
:
user
=
0.00
sys
=
0.00
,
real
=
0.00
secs
]
[
GC
[
PSYoungGen
:
4755K
->
1528K
(
5632K
)
]
4811K
->
1584K
(
18944K
)
,
0.0013799
secs
]
[
Times
:
user
=
0.00
sys
=
0.00
,
real
=
0.00
secs
]
[
GC
[
PSYoungGen
:
4631K
->
1496K
(
5632K
)
]
4687K
->
1552K
(
18944K
)
,
0.0010990
secs
]
[
Times
:
user
=
0.00
sys
=
0.00
,
real
=
0.00
secs
]
Heap
PSYoungGen
total
5632K
,
used
2561K
[
0x00000000ff900000
,
0x0000000100000000
,
0x0000000100000000
)
eden
space
4096K
,
26
%
used
[
0x00000000ff900000
,
0x00000000ffa0a448
,
0x00000000ffd00000
)
from
space
1536K
,
97
%
used
[
0x00000000ffd00000
,
0x00000000ffe76020
,
0x00000000ffe80000
)
to
space
1536K
,
0
%
used
[
0x00000000ffe80000
,
0x00000000ffe80000
,
0x0000000100000000
)
ParOldGen
total
13312K
,
used
56K
[
0x00000000fec00000
,
0x00000000ff900000
,
0x00000000ff900000
)
object
space
13312K
,
0
%
used
[
0x00000000fec00000
,
0x00000000fec0e000
,
0x00000000ff900000
)
PSPermGen
total
21504K
,
used
2445K
[
0x00000000f9a00000
,
0x00000000faf00000
,
0x00000000fec00000
)
object
space
21504K
,
11
%
used
[
0x00000000f9a00000
,
0x00000000f9c63400
,
0x00000000faf00000
)
|
新生代佔一半大小(10m),倖存區爲3:1:1(6m:2m,2m),觸發了1次gc,回收了7m左右空間,沒有使用老年代。對於這種臨時對象,減小老年代的使用是gc優化的關鍵。
1
2
3
4
5
6
7
8
9
10
11
|
D
:
\
>
java
-
Xmx20m
-
Xms20m
-
XX
:
NewRatio
=
1
-
XX
:
SurvivorRatio
=
3
-
XX
:
+
PrintGCDetails
JVMXmn1
[
GC
[
PSYoungGen
:
5954K
->
1624K
(
8192K
)
]
5954K
->
1624K
(
18432K
)
,
0.0023152
secs
]
[
Times
:
user
=
0.00
sys
=
0.00
,
real
=
0.00
secs
]
Heap
PSYoungGen
total
8192K
,
used
7059K
[
0x00000000ff600000
,
0x0000000100000000
,
0x0000000100000000
)
eden
space
6144K
,
88
%
used
[
0x00000000ff600000
,
0x00000000ffb4ecb8
,
0x00000000ffc00000
)
from
space
2048K
,
79
%
used
[
0x00000000ffc00000
,
0x00000000ffd96020
,
0x00000000ffe00000
)
to
space
2048K
,
0
%
used
[
0x00000000ffe00000
,
0x00000000ffe00000
,
0x0000000100000000
)
ParOldGen
total
10240K
,
used
0K
[
0x00000000fec00000
,
0x00000000ff600000
,
0x00000000ff600000
)
object
space
10240K
,
0
%
used
[
0x00000000fec00000
,
0x00000000fec00000
,
0x00000000ff600000
)
PSPermGen
total
21504K
,
used
2445K
[
0x00000000f9a00000
,
0x00000000faf00000
,
0x00000000fec00000
)
object
space
21504K
,
11
%
used
[
0x00000000f9a00000
,
0x00000000f9c63400
,
0x00000000faf00000
)
|
^^