HotSpotVM中垃圾回收的概念

说明

  • ==本文摘自【MemoryManagement-Whitepaper-1-150020.pdf】并转译,本文并不是完整的转译,部分地方有删减;==
  • ==本人水平有限,如有不正确的地方烦请指出,感激不尽。==

概述

一个垃圾回收器的责任有:
- 分配内存
- 确保任何引用的对象保持在内存中
- 在执行代码中,恢复引用不可抵达的对象所占用的内存

对象有被引用称为活动,不再引用的对象被认为是死的,称为垃圾,找出和释放这些垃圾对象的空间的过程称为垃圾回收。

垃圾回收解决了很多问题,但不是全部问题内存分配问题,例如,你可以创建一个对象然后无限引用直到耗尽可用内存。垃圾回收也是一个复杂的任务,本身也会消耗大量的时间和资源。

垃圾回收器用来处理组织内存、分配和释放空间的算法是非常精确的,但对程序员屏蔽,空间通常是从一个称为堆的内存池中分配的。

垃圾回收的时间取决于垃圾回收器,通常来说,当整个堆或堆的一部分被充满或达到它的占用率阈值时就会进行垃圾回收。

在堆中要找出一块一定规模大小且未被使用的内存来完成分配请求,是一个很困难的任务,在目前大多数动态内存分配算法中的主要问题是如何避免影响内存分配和释放的碎片问题。

值得拥有的垃圾回收器特性

一个垃圾回收器必须是安全和可靠的,意思就是说存活对象必须永远不会被错误释放,并且垃圾无人认领时间也应该小于一个收集周期。

垃圾回收器的操作效率也是一个值得拥有的特性,在程序没有运行区间没有长时间的停顿,然而,像大多数计算机相关系统一样,经常需要在时间、空间和频率之间进行权衡。例如,如果堆容量太小,回收很快但堆空间很快就被充满,从而导致更大的回收频率。反之,如果堆容量太大,堆空间很久才被充满并且回收频率也会降低,但会导致回收时间很长。

垃圾回收器另外一个值得拥有的特性是碎片的限制。当内存被垃圾对象释放的时候,释放的空间很小块并且还分散在各个区域,从而导致没有足够大的连续空间给大对象分配。有一种叫压缩的方法用来消除碎片,在下面的垃圾回收器的设计选择中有讨论。

可拓展性也是非常重要。分配不应该成为多线程应用在多处理器系统中的拓展瓶颈,并且回收也不应该成为瓶颈。

设计选择

在设计或选择一个垃圾回收算法时需要作出很多选择:
- 串行和并行,在串行回收器中,同一时刻只能有一件事在进行。例如,在多颗CPU有效的情况下,只有一颗用来执行回收。当使用并行回收的时候,垃圾回收的任务就会分隔成几个部分并且这些部分会同时运行在不同的CPUS上,同时进行的操作使得回收很快完成,以牺牲一些额外的复杂性和潜在的碎片为代价。
- 并行和停止世界(Stop-the-world),当停止世界垃圾回收执行的时候,在回收区间,应用完全被挂起不被执行。然而,一些垃圾回收任务可以并行执行,意思就是和应用程序一起执行。通常来说,并行的垃圾回收器可以并行的做更多的事,但偶尔也会有一些停止世界停顿。停止世界垃圾回收比并行回收简单,因为堆是暂时冻结并且对象在回收区间没有改变。它的缺点就是会让应用程序在回收区间不可用。相应的,并行垃圾回收的停顿时间就会比较短,但这个回收器需要额外的注意,因为它在对应用程序同时更新对象上进行操作,这会增加并行回收器的开销,同时也会影响性能和请求更大的堆空间。
- 压缩、非压缩、复制,在垃圾回收器确定了内存中哪些对象是存活的哪些对象是垃圾对象之后,它就会压缩内存,它会把所有存活对象移动到一起然后完全回收剩余内存。在压缩过后,它可以很快很轻松的在第一个释放区域分配新对象,可以使用一个简单的指针跟踪下一个可用于对象分配的位置。和压缩回收器对比的情况下,非压缩回收器释放垃圾对象使用的空间。例如,它不会像压缩回收器一样移动所有存活对象去创建一个大的可用区域。非压缩回收器的优点是可以很快的完成垃圾回收,缺点是产生内存碎片。一般来说,从释放空间的堆中(a heap with in-place deallocation)分配空间比在压缩过的堆中分配空间要更大消耗,它可能需要搜索堆找到一块连续的空间来满足新的大对象的创建。第三种方式是复制回收器,它会复制存活对象到不同的内存区域。这个算法的优点是源内存区可能为空,可以很快很简单的响应随后而来的分配请求,但缺点是复制时需要额外的时间和请求时需要额外的空间。

性能标准

有一系列的标准来衡量垃圾回收器的性能,包含以下内容:
- 吞吐量,不是消耗在垃圾回收的时间比例,是一段时间内的综合评估结果。
- 垃圾回收开销,吞吐量的对立面,就是消耗在垃圾回收的时间百分比。
- 停顿时间,当垃圾回收进行时,应用程序的停止时间长度。
- 回收频率,垃圾回收多长时间进行一次,相对于应用程序执行来说。
- 空间,容量的度量,例如堆大小。
- 及时性,在对象变成垃圾时到该内存变成有效时的时间。

交互性强的应用需要低的停顿时间,对于非交互性强的应用来说,整体执行时间才是更重要的。
及时性的应用要求垃圾回收停顿和在任何时期消耗在回收器上的时间比例都小于上限。而对于运行在个人电脑或内置系统来说则需要低的资源消耗。

分代回收

当使用分代回收技术的时候,就是将内存区分为代,根据不同年龄来分隔对象。比较常用的两种分代方式就是:年轻对象和老年对象。

在不同代中可以使用不同的垃圾回收算法,每种算法都有基于对应区域进行过优化。一般来说垃圾回收都会遵循一些守则,比如著名的weak generational hypothesis,很多程序语言都有垃圾回收应用,其中就包含Java:
- 大多数的分配对象在长时间内没有引用,它们就是那些死亡的年轻对象;
- 少数老年对象引用年轻对象的引用退出。

年轻代回收的发生比例相对较大,并且它们还可以快速而有效的完成,因为年轻代的空间通常很小,并且包含很多不再引用的对象。

在年轻代中的部分幸存下来的对象通常会晋升或终身待在老年代。请看下图:

figure 1

老年代的空间通常比年轻代大得多并且它还可以缓慢扩大,由此导致的结果就是,老年代的回收通常是比较罕见,并且完成回收的时间也更长。

选择年轻代的垃圾回收算法时通常会着重考虑速度方面,因为年轻代的回收是比较频繁的。对于另外一方面,老年代的垃圾回收算法通常会着重考虑空间使用率方面,因为老年代占用了堆的大部分空间并且老年代的算法必须可以很好的工作在低垃圾密集的环境。

猜你喜欢

转载自blog.csdn.net/Android_app/article/details/76655773