垃圾回收算法手册读书笔记(一)引言

引言

显式内存释放 vs 自动垃圾回收

几乎所有的语言都动态内存的分配,然而对于动态内存的回收,不同的语言与平台有着不同的机制。

其中C/C++采用显式的内存回收,允许程序员在显式的释放不再需要的对象。一方面显式内存释放可以使程序员获得更加细粒度的操作内存的能力,然而却会在另一方面增加程序出错的风险,例如过早回收对象导致的悬挂指针,以及忘记释放对象导致的内存泄漏,并且这两个问题在多线程环境下更为严重。开发者需要投入相当大的精力去精心处理内存相关的问题。

然而对于java等具备自动内存管理的平台,似乎不存在相关问题,垃圾回收机制的使用使得程序员不在需要关心一个对象在不再被使用后的释放工作,然而天下没有免费的午餐,开发人员普遍认为,垃圾回收通常会在内存吞吐量以及垃圾回收停顿时间方面引入一些不可接受的开销,使得垃圾回收机制很难应用于一些对时间非常敏感的实时程序。垃圾回收机制在一方面方便开发人员的同时,另一方面却有一些问题需要开发人员去考虑。对于一个应用而言,垃圾回收调优是开发人员绕不过去的一个坎。一个应用采用什么垃圾回收策略,如何调整垃圾回收器的参数使得其在特定应用环境下性能得到最大化,是一个值得研究的问题。诚然垃圾回收并不是解决所有内存相关编程错误的银弹,然而其带来的好处也是显而易见的,因此开发人员充分了解垃圾回收机制的运作原理对于垃圾回收的调优工作大有裨益

垃圾回收算法的一些指标

  • 安全性:任何时候不能回收存活对象
  • 吞吐量:通常用标记/构造率来衡量这一指标,它标识回收器与赋值器活跃度的比值
  • 完整性与及时性:回收过程是完整的,即所有垃圾最终都应得到回收;及时性则体现在于对象成为垃圾后能否被及时回收
  • 停顿时间:垃圾回收过程中,赋值器(应用)的停顿时间,对于某些应用,太长的停顿时间是不可接受的
  • 空间开销:不同的自动内存管理策略会产生不同程度的开销

术语

本段介绍一些之后会用到的一些术语,并且给出定义

赋值器

赋值器用于执行应用代码对内存进行分配,包括分配新的对象,修改对象之间的应用关系

赋值器根

赋值器根是一个有限的指针集合,赋值器可以不经其他对象直接访问到这些指针,实际情况下根通常包括静态/全局存储以及线程本地存储(例如线程栈)。赋值器通过根访问堆中对象,当一个对象不被赋值器根直接或间接引用,那么赋值器无法再访问到该对象,称该对象不可达

回收器

执行垃圾回收代码,找到不可达对象并将其回收

存活性与可达性

  • 存活性:某一对象在后续的执行中可能会被访问到,那么称该对象是存活的
  • 可达性:某一对象被赋值器根直接或者间接引用,称该对象是可达的

赋值器无法访问的对象必然不是存活的,而可达对象则有可能存活(在之后被赋值器访问),对于回收器而言,可达性等价于存活性,尽管在严格意义上并不准确(这也是造成内存泄漏的关键原因)

局部性

局部性又分为时间局部性空间局部性

满足如下条件,则称该程序具有良好时间局部性

  • 程序一旦访问某个内存地址,那么其很可能在不久之后再次访问该地址

满足如下条件,则称该程序具有良好空间局部性

  • 程序一旦访问某个内存地址,那么其很可能在不久之后再次访问该地址附近的数据

(cpu)高速缓存友好

高速缓存友好与局部性紧密联系,一般一个程序具有良好的局部性,那么该程序是对高速缓存友好的