java 垃圾自动回收

 Java虚拟机的一个强大之处在于其提供垃圾自动回收,对开发人员掩盖了内存分配和回收的细节。本篇将探索JVM的内存分配和垃圾回收机制,以在内存分析实战中提供一些理论和实践参考。
1.    从理论开始
1.1.垃圾检测
任何虚拟机的回收算法都包括两个步骤:检测垃圾和回收垃圾。当一个对象被创建时,其是活动的对象,此时其是可用的,而在运行过程中,该对象的引用不再被使用,这时该对象就成为垃圾,一般采用两种方式来区别活动对象和垃圾对象:引用计数和跟踪。当一个对象被其它对象引用时,其引用计数加1,当不再被其它对象引用时,计数减1,当其引用计数为0时,该对象就成为垃圾,引用计数的缺点是无法检测循环引用和维护引用计数的代价,在现代虚拟机中一般不采用该方式。而跟踪指的是虚拟机追踪从根对象出发的有向对象图,如果一个对象不能被追踪到,则该对象为垃圾,采用追踪算法的垃圾回收器也叫标记并回收回收器(见下图,可以形象地理解为在堆空间中引入了重力场,参见http://developer.51cto.com/art/200610/32793.htm )。

图1 初始状态

图2 TR1-A链和TR2-D链断开,A、B、C、D掉入回收池

图3 A、B、C、D四个对象被回收
1.2.避免堆碎片
在进行垃圾回收之后,由于内存分配时,垃圾对象和活动对象可能相邻存在,则可能会在堆中出现堆碎片,采用标记并回收回收器的虚拟机一般采用两种方法来对付堆碎片:压缩和拷贝。压缩回收是指当进行垃圾回收之后,将剩下的活动对象推向堆的另一端,则当垃圾回收完毕之后在另一端形成连续的堆。拷贝回收指的是保持两个同样大小的堆,在对一个队进行垃圾回收过程中,对于检测出来的活动对象拷贝到另一个堆并连续存放。参见下图

图4 拷贝收集和压缩手集
1.3.分代回收
拷贝回收的一个缺点在于有些对象是长期存在的,但在回收过程中仍然必须将这些对象多次拷贝,分代回收指的是,对不同年龄(在内存存在的时间的长短)将对象放入不同的代堆中,并对不同的代堆采用不同的回收算法。事实上,大部分的对象属于“短命”对象,我们可以更多地对年轻的代堆进行垃圾回收,而对于年老的代堆则减少回收频度。
1.4.垃圾回收器设计决策
?    顺序执行垃圾回收VS并行垃圾回收:在顺序执行垃圾回收器中,即使系统拥有多个处理器,也只有一个处理器会执行垃圾回收,相比之下,并行垃圾回收具备更好的垃圾回收性能,但因此必定引入更多的复杂性和潜在的内存碎片。
?    并发执行VS停止并回收:停止并回收指在进行垃圾回收时停止应用线程的执行,而并发执行垃圾回收器在大部分情况下与应用线程并发执行,当然,部分操作仍然需要在停止应用线程的情况下执行,并发回收对应用线程的停止时间更短,但相比而言,并发执行垃圾回收器将占用更多的空间并有可能对系统性能产生影响。
?    压缩VS不压缩VS拷贝:随着对象的消亡,JVM的堆空间将不可避免地存在碎片:一种方式是对碎片进行压缩,付出的代价是垃圾回收时更多的操作,得到的好处是能够快速分配;一种方式是不进行压缩,好处是垃圾回收更快,但分配算法将更加复杂;另外一种是拷贝,即将存活的对象拷贝到一个新的空间段上,之后将旧的对象全部销毁,好处是垃圾回收快,内存分配快,但必须付出更多的空间代价。
1.5.性能度量
?    吞吐量(Throughput):吞吐量 = (总执行时间-垃圾回收时间)/总执行时间
?    暂停时间(Pause time):垃圾回收导致的应用的暂停时间
2.    Sun HotSpot JVM实战
2.1.JVM分代垃圾回收
JVM的堆空间分成年轻代(Young Gen)、年老代(Old Gen)和持久代(Perm Gen),其中年轻代用于放置新创建的对象,而对象在经过几次的垃圾回收后仍然没有被回收,则将其转移到年老代,持久代用于放置一些为JVM本身的方便性而使用的对象,譬如类定义、方法定义、常量、代码段等。年轻代又分为一个Eden区和两个Survivor区, 而总有一个Survivor区是空的,随着每一次的垃圾回收,从Eden区和非空Survivor区的存活对象拷贝到空Survior区,如果Survior空间不足,则直接拷贝到年老区中,并将刚经历过回收的区空间返回到堆空间,此时两个Survivor的角色做了个转换(空的变成非空,非空的变成空的)。当一个对象经过多次回收仍然存在,则将其转入年老区。Sun HotSpot JVM对不同代将使用不同的垃圾回收算法。

图5 Sun HotSpot VM堆分代

图6 年轻代垃圾回收示意图
2.2.内存分配
对于大块的连续内存,使用bump-the-pointer技术,内存分配将非常简易和快速。对于多线程的场景,情况稍微复杂,内存分配必须是线程安全的,这可能导致内存分成为系统的瓶颈。Sun HotSpot JVM使用所谓的Thread-Local Allocation Buffers (TLABs)技术来解决这个问题,通过指定给每个线程一定的Buffer空间,线程在内存分配时,将尽量从此空间上分配,由于空间是独享的,因此分配将非常地快速,当然相应的,可能会造成空间的浪费。
2.3.不同垃圾回收器比较
2.3.1.垃圾回收方式
垃圾回收器名称    年轻代回收    年老代回收    压缩
Serial Collector    单线索程,顺序回收    单线程,顺序回收    是
Parallel Collector    多线程,并行回收    单线程,顺序回收    是
ParallelCompacting Collector    多线程,并行回收    多线程,并行回收    是
Concurrent Mark-Sweep (CMS) Collector    多线程,与应用并发回收    多线程,与应用并发回收    否

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值