详解Java垃圾收集算法
上一篇 / 下一篇 2009-09-03 16:16:49 / 个人分类:JAVA
Java语言建立了垃圾收集机制,用以跟踪正在使用的对象和发现并回收不再使用(引用)的对象。该机制可以有效防范动态内存分配中可能发生的两个危险:因内存垃圾过多而引发的内存耗尽,以及不恰当的内存释放所造成的内存非法引用。51Testing软件测试网9K)Y:M9\'eK*O
51Testing软件测试网/LD l8|!D$ls4^*E%u51Testing软件测试网\:q n@PPXB
@Sf{(s/r2tf0 垃圾收集算法的核心思想是:对虚拟机可用内存空间,即堆空间中的对象进行识别,如果对象正在被引用,那么称其为存活对象,反之,如果对象不再被引用,则为垃圾对象,可以回收其占据的空间,用于再分配。垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能,因此需要开发人员做比较深入的了解。51Testing软件测试网(_F m'B:zt1g \L_&]:JB'p
U;a4C.zi,g"fU0
A5DD(s({ t7mf-}4O051Testing软件测试网5~JsT4WDg9m4o:`2.触发主GC(Garbage Collector)的条件
%K-{4`o+i_:^o f07I.y)oD.E(r4y![0
D|0]vBn0? ]`I)G \'cp0 JVM进行次GC的频率很高,但因为这种GC占用时间极短,所以对系统产生的影响不大。更值得关注的是主GC的触发条件,因为它对系统影响很明显。总的来说,有两个条件会触发主GC:51Testing软件测试网,L!A{&E _9qv
,K(t~$DTFNG0 51Testing软件测试网Q^ Y6TGz+E(QcHL.Y
51Testing软件测试网8Xa2L'a"q6r4l&C①当应用程序空闲时,即没有应用线程在运行时,GC会被调用。因为GC在优先级最低的线程中进行,所以当应用忙时,GC线程就不会被调用,但以下条件除外。51Testing软件测试网g@i$Uy%A)IO
`iWdpY.z0 51Testing软件测试网 a/y X+Yl7b/U4Od)j/o
YI:Y/R|v*X4[0 ②Java堆内存不足时,GC会被调用。当应用线程在运行,并在运行过程中创建新对象,若这时内存空间不足,JVM就会强制地调用GC线程,以便回收内存用于新的分配。若GC一次之后仍不能满足内存分配的要求,JVM会再进行两次GC作进一步的尝试,若仍无法满足要求,则 JVM将报“out of memory”的错误,Java应用将停止。
$M w;cA)?~ T{'sQR{X1[051Testing软件测试网0Y6c,KT+o`9w `s8g0rPW'TOc-o:C051Testing软件测试网IF;G7S,M
由于是否进行主GC由JVM根据系统环境决定,而系统环境在不断的变化当中,所以主GC的运行具有不确定性,无法预计它何时必然出现,但可以确定的是对一个长期运行的应用来说,其主GC是反复进行的。51Testing软件测试网Nv.u?~+gP B
D4N ~2xX-g\#e;i2t&B0 51Testing软件测试网&YFtwBAs
51Testing软件测试网k.Ncp0])o*Ic3.减少GC开销的措施51Testing软件测试网E(HyRXf%c1Y
51Testing软件测试网sw{N+]7g#Bf8L!p;IfLp051Testing软件测试网*hM.~$v _P
根据上述GC的机制,程序的运行会直接影响系统环境的变化,从而影响GC的触发。若不针对GC的特点进行设计和编码,就会出现内存驻留等一系列负面影响。为了避免这些影响,基本的原则就是尽可能地减少垃圾和减少GC过程中的开销。具体措施包括以下几个方面:
2[3z}7~'L04`&y!w*X@8A#s!Q-^-O0
'M%Z|/zu3Fa051Testing软件测试网~n9J,}'b*[-r-k(1)不要显式调用System.gc()51Testing软件测试网M|k)]i2foAZ
Uz"gJuK']3a2`0此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。51Testing软件测试网BN(k_5|s3k9A
hN-i%[:?MC5t8Y3[0
Xv5~n#^ |;uu&Ks5K051Testing软件测试网.q.A8b{(O(2)尽量减少临时对象的使用51Testing软件测试网8~w*LXh)J:JUz
51Testing软件测试网_L s BFJ p)g0{'ub临时对象在跳出函数调用后,会成为垃圾,少用临时变量就相当于减少了垃圾的产生,从而延长了出现上述第二个触发条件出现的时间,减少了主GC的机会。51Testing软件测试网R%_%[ c#lc
51Testing软件测试网B)R'HI2P:u9G#bT^oBK051Testing软件测试网4AB g1eh*_
(3)对象不用时最好显式置为Null
.p7cp$b'pDK&{SZ5V7_0j+{L9Y B0 一般而言,为Null的对象都会被作为垃圾处理,所以将不用的对象显式地设为Null,有利于GC收集器判定垃圾,从而提高了GC的效率。51Testing软件测试网j.b~:Y0qOsQ!vC
(U;Vic7u&o0
Kz&^,G(I4Ah051Testing软件测试网jJ-Z;Bs"}|[6mj(4)尽量使用StringBuffer,而不用String来累加字符串(详见blog另一篇文章JAVA中String与StringBuffer)
'EPE'L%_Mu051Testing软件测试网(a+n;V*R y!bO6S由于String是固定长的字符串对象,累加String对象时,并非在一个String对象中扩增,而是重新创建新的String对象,如Str5=Str1+Str2+Str3+Str4,这条语句执行过程中会产生多个垃圾对象,因为对次作“+”操作时都必须创建新的String对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。避免这种情况可以改用StringBuffer来累加字符串,因StringBuffer是可变长的,它在原有基础上进行扩增,不会产生中间对象。51Testing软件测试网2~,yL)M$Z9S'} _}
i^L7Y$Mo,MB0
TD:izj2sa051Testing软件测试网x'Uc9E?G%y,E(5)能用基本类型如Int,Long,就不用Integer,Long对象
p)v2C{4@y B)^B'N0(^3IHP:r6Fj D0 基本类型变量占用的内存资源比相应对象占用的少得多,如果没有必要,最好使用基本变量。
]U2K7]v O051Testing软件测试网4yQ|*I.D.uz)J.p`O051Testing软件测试网*V%`Su$f?$Y1Y.YXEu6R
(6)尽量少用静态对象变量
3B%K){$](b051Testing软件测试网$Cspe$MY静态变量属于全局变量,不会被GC回收,它们会一直占用内存。51Testing软件测试网)H~2l J5w*Y*o$Nz N9r
51Testing软件测试网 x|&})vV5}9xp*y51Testing软件测试网fLP-r9B f
x7{F9p @4v0 (7)分散对象创建或删除的时间
%Xr z,T;WYV`0R:oDh1sJwDmy0 集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增加主GC的频率。集中删除对象,道理也是一样的。它使得突然出现了大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC的机会。51Testing软件测试网cqhGZZ-o
ois\\q0Y9Z0
w-V s%JHu051Testing软件测试网2`?"o}j4.gc与finalize方法
jm"I_G_051Testing软件测试网a$Ol1uD,l+Q⑴gc方法请求垃圾回收51Testing软件测试网?O$SN"Au v Gs
D@Z"G6Mt0 使用System.gc()可以不管JVM使用的是哪一种垃圾回收的算法,都可以请求Java的垃圾回收。需要注意的是,调用System.gc()也仅仅是一个请求。JVM接受这个消息后,并不是立即做垃圾回收,而只是对几个垃圾回收算法做了加权,使垃圾回收操作容易发生,或提早发生,或回收较多而已。
;kPxZf SPm*U0N0I0i4XjRp2P0 51Testing软件测试网if/J"GMT F
51Testing软件测试网N)N^&s g2`HL_ n⑵finalize方法透视垃圾收集器的运行
0x9E m0U4B0(um6waD0 在JVM垃圾收集器收集一个对象之前 ,一般要求程序调用适当的方法释放资源,但在没有明确释放资源的情况下,Java提供了缺省机制来终止化该对象释放资源,这个方法就是finalize()。它的原型为:51Testing软件测试网ACGq)Ex4Up%s
?B*\ [`+n|a0 protected void finalize() throws Throwable
o6}&}'N4H/dL v051Testing软件测试网)?-XJ!k6}/I51Testing软件测试网+P'E+Q1zX;E1\B)c
51Testing软件测试网 j(J0hMK{:nD在finalize()方法返回之后,对象消失,垃圾收集开始执行。原型中的throws Throwable表示它可以抛出任何类型的异常。51Testing软件测试网3|!f/?:\s?
jDk#U6s2H$` Z1sA0 51Testing软件测试网u]6yv_:[3N ~-h
51Testing软件测试网Rbe5_)Xm5E因此,当对象即将被销毁时,有时需要做一些善后工作。可以把这些操作写在finalize()方法里。51Testing软件测试网gh TQMPys
5]5B?njMU \0 51Testing软件测试网Kz~8L;n*LKA
p{J)yLT&Z@kh+@0 以下是引用片段:
5xV(k wz-En-\051Testing软件测试网E{.A/J;Nn{R v5Iw LPsS5S7n051Testing软件测试网:h^e? z;d7c&?:S
protected void finalize(){
x5zx_U+u _[6c N0g6X)X_SrnR0 // finalization code here51Testing软件测试网`"_Z%K)g0t"Q-d`0^6q
}51Testing软件测试网(f
jH ZGB/z
51Testing软件测试网p/R;c0J3^ ~5Gxof
51Testing软件测试网x0T5nKPv(p⑶代码示例51Testing软件测试网8RXO!w!I#U K
51Testing软件测试网YN` J)S|6M0n@m0w以下是引用片段:51Testing软件测试网"p}Z\#|ex%h3[wUN
51Testing软件测试网o {#\ks class Garbage {
6o gSR.M+BeM0 int index;51Testing软件测试网t2LZ {&jjb
static int count;
ed-EGi~4d OP{!N051Testing软件测试网?z9J*JY*Pb oD9}Garbage() {