JAVA性能优化权威指南 读书笔记(三)

HotSpot VM的垃圾收集机制

  首先我们需要明确这个知识点,我们在java中所说的垃圾收集机制指的都是在java堆中的垃圾收集。Java虚拟机规范要求所有的JVM都能适当的回收闲置内存,垃圾收集器的运行方式和执行效率对于应用的性能和相应有着极大的影响。

分代垃圾收集

  在HotSpot VM中使用分代垃圾收集器,这个逻辑基于以下事实:

      大多数分配对象的存活时间都非常短

      存活时间久的对象很少引用存辉时间短的对象

  对于大多数应用而言,这个两个特征能够比较明确的得到体现,所以依据这些逻辑,在HotSpot VM中堆中的内容被分为三个部分:

      新生代:新创建的对象会被分配到这里,对于整个堆而言一般比较小,垃圾收集平凡,并且其中的对象大部分被收集得很快(这里指存活时间比较短)。

  老年代:在新生代中如果一个对象存活度过一定的周期之后,那么HotSpot VM认为这个对象将会比较长久的存在,那么就会把对象提升到老年代中。老年代的占比比较大,并且其中的垃圾收集次数较少,并且每次收集能够销毁的对象比较少(相对比例而言)

  永久代:这个虽然称之为代,但是事实上这个部分不与新老两个代进行代际的转移,HotSpot VM只是拿来存放元数据(类的数据结构、保留字符串等)

 

  收集方法,垃圾收集器通过卡表来进行查找老——新之间的引用,将老年代的数据以每512个字节划分为若干个快。每次老年代对象中引用新生代的字段发生变化的时候卡表的状态便被设置为脏,垃圾收集器只需要在脏卡中查找老——新引用的变化。

      HotSpot VM字节码解释器和JIT编译器使用些屏障维护卡表,就是一段维护卡表状态的代码,每次在有引用的更新的时候就会执行这段代码,这虽然添加了部分操作量但是极大的减少了垃圾收集器的工作,所以整体上这个还是对于性能有极大的提升的。

分代垃圾收集的办法使得JVM可以通过不同的垃圾收集的策略和算法对于不同特征的堆内容进行特异性的收集,这个对于性能的优化就给我们提供了更多的空间。

新生代

     新生代的区域一般来说被分为三块,其中一块为Eden还有两块为Survivor,在这里我们为了方便解说就将Survivor分成S1S2分别对应两块Survivor

    在这里我们提供一个简单的垃圾收集的例子,假设一个垃圾收集就要开始,这个时候依据内存分配的情况EdenS1中存在对象,S2中空闲。

一般来说新分配的对象都会被生成在Eden中,当某次垃圾收集完成之后,在Eden依然存活的以及在S1中存活的对象会被转移到之前空置的S2中去,将之前有对象的S1Eden清空。然后直到进行下一次收集,Eden中剩下以及S2中剩下的对象被转移到空闲的S1中去......直到如果在转移过程中发现某些对象存在的时间过程,譬如说已经幸存超过10次垃圾收集,那么这些对象将会被提升到老年代中去。

详细的情况我们可以参见下面的图示:


----------------------------------------------------------------------------------------------------------------------------------------------


----------------------------------------------------------------------------------------------------------------------------------------------



----------------------------------------------------------------------------------------------------------------------------------------------


快速内存分配

  有一点可以清楚的看到,就是在之前的垃圾收集(新生代)之后,我们处于Eden中的空间总是空的,所以为了提升内存分配的效率可以直接使用指针碰撞的方法进行内存的快速分配。

  在分配开始时只需要检查topEden末端之间的空间是否符合需要,如果能够容纳,那么就直接分配空间出去,并把top指针往后移动至分配出去的空间之末。

  注:在这里由于java是一个允许多线程的语言,所以实际操作的时候是给予每个线程一个Eden中的缓冲区,并在这个给定的区域内进行指针碰撞,一般单个线程不会填满整个给定的缓冲区

垃圾收集器

  Serial收集器:这款收集器在新生代中使用之前描述的方法进行处理,而在老年代的收集中使用压缩标记清除的方式对于内存进行收集。这里这两种的收集方式都是会STOP-THE-WORLD的方式进行处理,这种方式顾名思义是停止了所有JVM内的线程进展,这使得垃圾收集器能够高效以及完全的模式进行垃圾收集,但是随之而来的问题是垃圾收集的过程中其他的服务进程全部会被停滞,在这个时间段之中会极大的影响响应的速度。(特别是部分响应时间有比较高要求的应用)

    Serial收集器对于大多数停顿时间要求不高和在客户端运行的应用中使用比较广泛,它只需几百兆java堆就能有效管理许多应用,并在最差的情况下也能保持比较短暂的停顿。

注:标记压缩方法,在回收老年代的对象的过程中,将存活的对象移到堆的头部,最终收集完成之后所有空余的位置留在尾部,这种方法就可以在之后的内存分配中使用前文所提到过的‘指针碰撞’进行快速的内存分配,在垃圾收集的时候虽然会产生额外的性能消耗,但是显然设计者认为这个设计是值得的。

  Parallel收集器:这款收集器是以吞吐量为追求的,一般也被称为Throughput收集器,它的操作模式可以说和Serial基本一致,新生代使用Stop-the-world,老年代使用标记压缩。但是它的特色就是使得Minor GC以及Full GC可以在同时进行,也就是将老年代和新生代的垃圾收集进行并发处理,这个提升了垃圾收集的整体效率,所以它能够提供更好的吞吐量的体现。

注:吞吐量值得是在一定时间内对于任务的处理数量,所以我个人将这个视作性能在时间上的积分,而通过提高垃圾收集的时间效率能够降低垃圾收集的时间,减少了应用不能提供服务的整体时间,在系统和硬件条件不变的情况下就能提供更多的吞吐量。

 

  Mostly-Concurrent收集器:这种类型的收集器就和之前的非常大的不同了,为了使得系统不至于由于垃圾收集的原因造成较大的延迟波动,所以在耗时较高的老年代垃圾收集中使用了非Stop-the-world的模式,并发标记收集,在正式收集之前就在并发线程中标记好需要收集的内容,只在开始和最后收集执行的时候产生两次简短的停顿。由于在这里收集的时候只需要依照之前的标记进行执行,不需要再进行判断,所以收集的过程停顿时间被降到很低的程度。

  但是依然有问题会出现,这种方式的垃圾收集由于是并发进行的,同时代码也在对于内存中的对象进行操作和执行,所以在并发标记阶段将会有不少对象在之后又被改动过,这个时候收集器引入了重新标记的方法,在第一次标记完成之后再对于期间有过个改动的对象进行遍历。为了进一步提高效率重新标记的之前还引入了预清除阶段,预清除阶段会重新标记一些在第一次标记阶段被改掉的对象,这将在重新标记阶段提示效率,减少重新标记产生的停顿。在标记完成之后采用的内存收集的方式并不使用标记-压缩的模式,这个特性使得内存的收集过程也可以和应用的线程是并行的,这进一步减少了停顿的时间。

总体来说CMS收集器的优势在于停顿时间短,但是这个收集器对于性能会有更高的要求,同时由于并发的问题其实并不能被完全避免,垃圾收集的结果难免会漏掉部分需要收集的垃圾,而且由于不使用标记-压缩的模式,导致在之后的内存分配中会有相比其他收集器的额外消耗。

  G1收集器:Garbage-First收集器是最新的收集器,在概念上颠覆了之前JVM中新生代和老年代的概念。该款收集器将java堆分成相同尺寸的区域,将一组区域标记分为一个带,当然在这里的一组区域可能不连续。

  G1收集器的操作方式是将区域中存活的对象转移到另一个区域中去,然后收集前者的区域,G1定期并发标记那些几乎是空的区域,这就是G1的核心思想,使用最小的消耗优先解放区域。

应用对于垃圾收集器的影响

  内存分配:由于垃圾收集这个任务的性质,可以预见的是当我们的内存中东西过多或者说是溢出的时候我们不得不启动垃圾收集这个过程,内存的大小以及应用中对于内存的使用方式将通过内存使用率极大的影响垃圾收集的频率。

  存活数据多少:显然垃圾收集器的使用时间是和存活对象的数量有关,越多的对象存活将会使得垃圾收集器需要遍历更多的对象。

  老年代的引用更新:老年代中引用更新也会需要垃圾收集器额外的注意,所以这也会影响垃圾收集的任务量。

 

  注意,对象池的设计能够在编码的时候提供更多的便利以及种种的好处,但是对于垃圾收集而言,池化的对象显然是Old-to-young引用更新的大户,并且由于池化的原因,这些对象会增加老年代的压力。综上我们在设计应用的时候要考虑到池化对象的优缺点并尽量平衡的使用。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值