本文主要是对常用的GC算法(引用计数法标记-清除法复制算法标记-清除算法)作出相关的说明,并对相关知识做简单的介绍。

一、什么是堆?

       堆指用于动态(即执行程序时)存放对象的内存空间。而这个对象,在面向对象的编程中,它指“具有属性和行为的事物”,然而在GC的世界中,对象表示的是“通过应用程序利用的数据的集合”。具体到Java堆,它是所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。(此处的对象实例可以理解为前面所说的对象,因为不仅仅Java有自动的GC,python、JavaScript等语言也有,所以在广义上说对象是更好的表述,当然,Java的数组也是分配在堆上的)。

二、GC算法的评判标准

GC算法的评判标准主要是以下4点:

1、吞吐量:即单位时间内的处理能力。

2、最大暂停时间:因执行GC而暂停执行程序所需的时间。

3、堆的使用效率:鱼与熊掌不可兼得,堆使用效率和吞吐量、最大暂停时间是不可能同时满足的。即可用的堆越大,GC运行越快;相反,想要利用有限的堆,GC花费的时间就越长。

4、访问的局部性:在存储器的层级构造中,我们知道越是高速存取的存储器容量会越小(具体可以参看我写的存储器那篇文章)。由于程序的局部性原理,将经常用到的数据放在堆中较近的位置,可以提高程序的运行效率。

三、可达性

所谓的可达性就是通过一系列称为“GC Roots”的对象为起点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是GC Roots到这个对象不可达)时,则说明此对象是不可用的。如下图所示,ABC可达,DE不可达。

那么那些对象可以作为GC Roots呢?以Java为例,有以下几种:

1、栈(栈帧中的本地变量表)中引用的对象。

2、方法区中的静态成员。

3、方法区中的常量引用的对象(全局变量)。

4、本地方法栈中JNI(一般说的Native方法)引用的对象。

注:第一和第四种都是指的方法的本地变量表,第二种表达的意思比较清晰,第三种主要指的是声明为final的常量值。

四、引用计数法

1、什么是引用计数法?

所谓的引用计数法就是给每个对象一个引用计数器,每当有一个地方引用它时,计数器就会加1;当引用失效时,计数器的值就会减1;任何时刻计数器的值为0的对象就是不可能再被使用的。

这个引用计数法时没有被Java所使用的,但是python有使用到它。而且最原始的引用计数法没有用到GC Roots。

2、优点

<1>可即时回收垃圾:在该方法中,每个对象始终知道自己是否有被引用,当被引用的数值为0时,对象马上可以把自己当作空闲空间链接到空闲链表。

<2>最大暂停时间短。

<3>没有必要沿着指针查找

3、缺点

<1>计数器值的增减处理非常繁重

<2>计算器需要占用很多位。

<3>实现繁琐。

<4>循环引用无法回收。

五、标记-清除算法

1、什么是标记-清除算法?

该算法分为标记和清除两个阶段。标记就是把所有活动对象都做上标记的阶段;清除就是将没有做上标记的对象进行回收的阶段。如下图所示。

  1. 优点

<1>实现简单

<2>与保守式GC算法兼容(保守式GC在后面介绍)

3、缺点

<1>碎片化:如上图所示,在回收的过程中会产生被细化的分块,到后面,即使堆中分块的总大小够用,但是却因为分块太小而不能执行分配。

<2>分配速度:因为分块不是连续的,因此每次分块都要遍历空闲链表,找到足够大的分块,从而造成时间的浪费。

<3>与写时复制技术不兼容:所谓写时复制就是fork的时候,内存空间只引用而不复制,只有当该进程的数据发生变化时,才会将数据复制到该进程的内存空间。这样,当两个进程中的内存数据相同的时候,就能节约大量的内存空间了。而对于标记-清除算法,它的每个对象都有一个标志位来表示它是否被标记,在每一次运行标记-清除算法的时候,被引用的对象都会进行标记操作,这个仅仅标记位的改变,也会变成对象数据的改变,从而引发写时复制的复制过程,与写时复制的初衷就背道而驰了。

六、复制算法

1、什么是复制算法?

复制算法就是将内存空间按容量分成两块。当这一块内存用完的时候,就将还存活着的对象复制到另外一块上面,然后把已经使用过的这一块一次清理掉。这样使得每次都是对半块内存进行内存回收。内存分配时就不用考虑内存碎片等复杂情况,只要移动堆顶的指针,按顺序分配内存即可,实现简单,运行高效。

  1. 优点

<1>优秀的吞吐量。

<2>可实现高速分配:复制算法不用使用空闲链表。这是因为分块是连续的内存空间,因此,调用这个分块的大小,只需要这个分块大小不小于所申请的大小,移动指针进行分配即可。

<3>不会发生碎片化。

<4>与缓存兼容。

3、缺点

<1>堆的使用效率低下。

<2>不兼容保守式GC算法。

<3>递归调用函数。

七、标记-压缩算法

1、什么是标记-压缩算法?

标记-压缩算法与标记-清理算法类似,只是后续步骤是让所有存活的对象移动到一端,然后直接清除掉端边界以外的内存。

  1. 优缺点

该算法可以有效的利用堆,但是压缩需要花比较多的时间成本。

八、保守式GC与准确式GC

1、保守式GC

所谓保守式GC就是“不能识别指针和非指针的GC”。

对于寄存器、调用栈、全局变量空间来说,都是不明确的根。例如调用栈中,装着函数内的局部变量和参数值。而局部变量,如C语言中的int、double这样就是非指针,但是也会有像void*这样的指针。

那么保守式GC会怎么检查不明确的根呢?1、是不是被正确对齐的值?(在32位CPU的情况下,为4的倍数)2、是不是指着堆内?3、是不是指向对象的开头?当然,这些只是基本的检查项目。

上面的检查方法会将一些非指针识别成指针。例如一个数值和一个地址,它们两个值相等,这个时候,那个值也可以被识别成指针。

保守式GC的优点是语言处理程序不依赖与GC。缺点为识别指针和非指针需要付出成本、错误识别指针会压迫堆、能够使用的GC算法有限。例如GC复制算法就不能使用,因为其可能会将非指针重写。

2、准确式GC

准确式GC能够正确识别指针和非指针的GC。正确的根的创建方法是依赖于语言处理程序的实现的。我们可以通过打标签、不把寄存器和栈等当作根的方法来实现。

其优点就是完全能够识别指针,能够使用复制算法等需要移动对象的算法。但是在创建准确式GC时,语言处理程序必须对GC进行一些支援,而且创建正确的根就必须付出一定的代价。

其实我们垃圾回收机的实现都不是仅仅用哪一种回收算法,都是将几个结合使用,特别是分代算法,后面我们会详细的介绍。

参考文献

《深入理解Java虚拟机》

《垃圾回收的算法与实现》

https://www.zhihu.com/question/60103311

几种常见GC算法介绍相关推荐

  1. 8种常见机器学习算法比较

    8种常见机器学习算法比较 2016-08-04 17:46 转载 陈圳 0条评论 雷锋网(搜索"雷锋网"公众号关注)按:本文转自刘志伟责编,在机器学习中选择一个恰当的算法十分重要, ...

  2. 常见特征检测算法介绍

    Camera系列文章 传感器融合是将多个传感器采集的数据进行融合处理,以更好感知周围环境:这里首先介绍Camera的相关内容,包括摄像头及图像知识基本介绍,OpenCV图像识别(特征提取,目标分类等) ...

  3. Java常见GC算法_垃圾收集器及内存分配_G1垃圾收集器

    常见GC算法 引用计数法: 每个对象都有一个计数器, 对象被引用一次, 计数器+1, 当对象引用失败一次. 计数器-1, 当对象计数器等于0, 说明对象没有被应用, 就可GC 优: 运行过程中, 可随 ...

  4. 【转载】四种常见系统架构介绍

    转自于 四种常见系统架构介绍 - 宇大..大 - 博客园软件架构(software architecture)就是软件的基本结构. 合适的架构是软件成功的最重要因素之一.大型软件公司通常有专门的架构师 ...

  5. 常见的 GC 算法介绍(Parallel/CMS/G1):温故而知新

    GC 是英文词汇 Garbage Collection 的缩写,中文一般直译为"垃圾收集".当然有时候为了让文字更流畅,也会说"垃圾回收".一般认为" ...

  6. 【JVM】一文搞懂常见GC算法

    文章内容 1.概述 2.如何确定垃圾对象? 3.GC算法 4.GC算法总结 5.常见的垃圾收集器 1.概述 GC目的:程序运行过程中可能会产生许多垃圾对象,持续占用内存会造成内存泄漏,最终可能导致内存 ...

  7. Java几种常见排序算法与代码实现

    前言: 排序算法也算是每年校招.春招.社招都会问到的问题,虽然每次复习了就忘,但是也可以隔一段时间又拿出来看看. 其中,排序方式指,内部还是外部排序.只需要内部内存就可以的称为内部排序,数据量太大需要 ...

  8. AI-常见机器学习算法介绍

    分享一个大牛的人工智能教程.零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请点击http://www.captainbed.net 机器学习算法分类 1. 监督式学习 工作机制:这个算 ...

  9. 用Python解析XML的几种常见方法的介绍

    这篇文章主要介绍了用Python解析XML的几种常见方法,包括快速的使用ElementTree模块等方法的实例介绍,需要的朋友可以参考下 一.简介 XML(eXtensible Markup Lang ...

最新文章

  1. Intel汇编程序设计-整数算术指令(上)
  2. 六个大坑,把“伟大的产品”秒成了渣
  3. oracle 移动日志文件,Oracle数据库移动数据文件、日志文件和控制文件
  4. 历代CPU最全明细参数表
  5. MiniFrameworkPHP开源框架
  6. 【API进阶之路】破圈,用一个API代替10人内容团队
  7. php 把图片转换成二进制流,php把图片转换成二进制流的方法
  8. 【人工智能】利用C语言实现KNN算法进行手写数字识别
  9. JAVA面试要点002_Git中fetch和pull的区别
  10. php上传文件测试代码,php 文件上传函数的超详细示例
  11. java就业班学什么呀_传智播客JAVA就业班的学习心得
  12. 激光防护屏 激光防护屏
  13. 程序员必须 知道的英语单词
  14. FFmpeg windows 录屏(录像)录音 实测
  15. LaTeX中文生僻字显示
  16. 基础30讲 第10讲 积分等式与积分不等式
  17. 70个JavaScript面试问题
  18. 数据结构使用c语言第5版答案,数据结构(c语言版)第五章答案.doc
  19. Python中的setattr()和getattr()
  20. vue.js 两个等号 == 和三个等号 ===的区别

热门文章

  1. 16个最热门的 Android Apps 推荐下载
  2. SpringAop中JoinPoint对象的使用方法
  3. 主机安全是什么意思?主机安全体检包含哪些方面?
  4. html转义es,Js特殊字符转义之htmlEscape()方法
  5. C#和Visionpro联合开发之运行图像程序
  6. DirectX11 使用几何着色器实现公告板效果
  7. 【流量代理】代理模式
  8. 农业物联网 锻造精准农业“标杆”
  9. QVariant的使用
  10. WEB漏洞攻防- SQL注入原理、判定方式、过滤及修复