热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

垃圾回收器的算法,垃圾回收算法与实现

引用计数算法有着诸多的优点,但它的缺点也是很明显的。整个过程分为两个阶段:标记阶段找到所有存活对象;清除阶段清除所有垃圾对象。它的整个过程可以描述为:标记所有的存活对象;通过重新调


1.引用计数算法


“参照计数”(Reference Counting )算法计算每个对象指向它的指针数,并在一个指针指向自己时将计数值加1。 删除指向自己的指针后,计数值将减少1。 如果计数值减少到0,则指向该对象的指针将不再存在,因此可以安全地丢弃。 可以直观地用下图表示。


引用计数算法的优点是内存管理开销在APP应用程序运行时分散,非常“平滑”,不需要因为垃圾回收而停止APP应用程序的运行。 另一个优点是空间参考的局部性很高。 当一个对象的引用计数值变为0时,系统不需要访问堆中其他页面上的设备。 此外,后面介绍的一些垃圾回收算法在回收之前遍历所有生存单元。 这可能会引起页面转换操作。 最后的引用计数算法提供了类似堆栈分配的方式,丢弃就回收。 接下来看到的一些垃圾回收算法是对象废弃后生存一段时间再回收。


引用计数算法有很多优点,但其缺点也很明显。 首先,您可以看到的是时间开销,每次创建或释放对象时都会计算引用计数值,从而产生额外的开销。 第二种空间开销,每个对象必须留出额外的空间来存储参考计数值,以保持自己参考的数目; 引用计数算法的最大缺点是无法处理环引用,如下图所示。


这里蓝色的两个对象既不能到达也不能回收。 因为它们互相参照,各自的计数值不是0。 这对引用计数算法来说是无能为力的,但其他垃圾回收算法能很好地处理环引用。


引用算法最有名的运用莫过于微软的COM技术,著名的IUnknown接口:


interfaceiunknown { virtual hresult _ stdcallqueryinterface,void**PPV}=0; virtualulong_stdcalladdref(=0; virtualulong_stdcallrelease(=0; }


这里的AddRef和Release是为了让组件本身能够管理生命周期,客户端程序只关心接口,而不需要关心组件的生命周期。 以下是一个简单的使用案例。


int main () { IUnknown* pi=CreateInstance ); IX* pix=NULL; hresult HR=pi-query接口(iid _ IX,) void * (pix ); if (安全(HR ) ) { pix-DoSomething; pix-Release (; (} pi-Release ); }上的客户端程序已经在CreateInstance中调用了AddRef,因此不需要再次调用,而是在使用接口后调用Release。 这将改变组件自身维护的计数值。 以下代码显示了一个简单的实现AddRef和Release的示例。


ULONG _stdcall AddRef () { return m_cRef; }ULONG _stdcall Release () if(-m_cref==0) { delete this; 返回0; } return m_cRef; }


在编程语言Python中,使用也是一种引用计数算法,如果对象的引用计数值为0,则调用__del__函数。 至于为什么Python选择引用计数算法,我读的文章说,因为Python是脚本语言,所以经常与C/C等语言进行交互,通过使用引用计数算法避免对象在内存中的更改因为Python还引入了gc模块来解决环引用问题,所以本质上python GC的方案是混合引用计数和跟踪(后面介绍的三种算法)两种垃圾回收机制。


2.标记-清除算法


“标记-清除”(朴素的黑猫-Sweep )算法依赖于确定可以通过一次全局遍历回收所有存活对象的对象。 遍历过程从根中找到所有可到达的对象,其他不可到达的对象是垃圾对象,可以回收。 整个过程分为两个阶段。 标记阶段会找到所有的生存对象。 逐步清除所有垃圾对象。


标记阶段


清除舞台

lign="left"> 

      相比较引用计数算法,标记-清除算法可以非常自然的处理环形引用问题,另外在创建对象和销毁对象时时少了操作引用计数值的开销。它的缺点在于标记-清除算法是一种“停止-启动”算法,在垃圾回收器运行过程中,应用程序必须暂时停止,所以对于标记-清除算法的研究如何减少它的停顿时间,而分代式垃圾收集器就是为了减少它的停顿时间,后面会说到。另外,标记-清除算法在标记阶段需要遍历所有的存活对象,会造成一定的开销,在清除阶段,清除垃圾对象后会造成大量的内存碎片。

3.标记-缩并算法

     标记-缩并算法是为了解决内存碎片问题而产生的一种算法。它的整个过程可以描述为:标记所有的存活对象;通过重新调整存活对象位置来缩并对象图;更新指向被移动了位置的对象的指针。

标记阶段:

 

清除阶段:

 

标记-压缩算法最大的难点在于如何选择所使用的压缩算法,如果压缩算法选择不好,将会导致极大的程序性能问题,如导致Cache命中率低等。一般来说,根据压缩后对象的位置不同,压缩算法可以分为以下三种:

1. 任意:移动对象时不考虑它们原来的次序,也不考虑它们之间是否有互相引用的关系。
2. 线性:尽可能的将原来的对象和它所指向的对象放在相邻位置上,这样可以达到更好的空间局部性。
3. 滑动:将对象“滑动”到堆的一端,把存活对象之间的自由单元“挤出去”,从而维持了分配时的原始次序。

4.节点拷贝算法

节点拷贝算法是把整个堆分成两个半区(From,To), GC的过程其实就是把存活对象从一个半区From拷贝到另外一个半区To的过程,而在下一次回收时,两个半区再互换角色。在移动结束后,再更新对象的指针引用,GC开始前的情形:

GC结束后的情形:

      节点拷贝算法由于在拷贝过程中,就可以进行内存整理,所以不会再有内存碎片的问题,同时也不需要再专门做一次内存压缩。,而它最大的缺点在于需要双倍的空间。

5.总结

      本文总共介绍了四种经典的垃圾回收算法,其中后三种经常称之为跟踪垃圾回收,因为引用计数算法能够平滑的进行垃圾回收,而不会出现“停止”现象,经常出现于一些实时系统中,但它无法解决环形问题;而基于跟踪的垃圾回收机制,在每一次垃圾回收过程中,要遍历或者复制所有的存活对象,这是一个非常耗时的工作,一种好的解决方案就是对堆上的对象进行分区,对不同区域的对象使用不同的垃圾回收算法,分代式垃圾回收器正是其中一种,CLR和JVM中都采用了分代式垃圾回收机制,但它们在处理上又有些不同,后面的文章再详细介绍这两种垃圾回收器的区别。

 更加详细请参见于:http://www.cnblogs.com/Terrylee/

 

更多内容:http://blog.csdn.net/wallwind


推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 本文介绍了OkHttp3的基本使用和特性,包括支持HTTP/2、连接池、GZIP压缩、缓存等功能。同时还提到了OkHttp3的适用平台和源码阅读计划。文章还介绍了OkHttp3的请求/响应API的设计和使用方式,包括阻塞式的同步请求和带回调的异步请求。 ... [详细]
  • 开发笔记:Python之路第一篇:初识Python
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Python之路第一篇:初识Python相关的知识,希望对你有一定的参考价值。Python简介& ... [详细]
  • 一面自我介绍对象相等的判断,equals方法实现。可以简单描述挫折,并说明自己如何克服,最终有哪些收获。职业规划表明自己决心,首先自己不准备继续求学了,必须招工作了。希望去哪 ... [详细]
  • Android系统启动过程分析一、Android平台架构首先贴一张Android系统架构图方便理解整个Android架构,这可以让我们从整体上对整个启动流程有个大概认知。可以看出整 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 本文是一位90后程序员分享的职业发展经验,从年薪3w到30w的薪资增长过程。文章回顾了自己的青春时光,包括与朋友一起玩DOTA的回忆,并附上了一段纪念DOTA青春的视频链接。作者还提到了一些与程序员相关的名词和团队,如Pis、蛛丝马迹、B神、LGD、EHOME等。通过分享自己的经验,作者希望能够给其他程序员提供一些职业发展的思路和启示。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • Servlet多用户登录时HttpSession会话信息覆盖问题的解决方案
    本文讨论了在Servlet多用户登录时可能出现的HttpSession会话信息覆盖问题,并提供了解决方案。通过分析JSESSIONID的作用机制和编码方式,我们可以得出每个HttpSession对象都是通过客户端发送的唯一JSESSIONID来识别的,因此无需担心会话信息被覆盖的问题。需要注意的是,本文讨论的是多个客户端级别上的多用户登录,而非同一个浏览器级别上的多用户登录。 ... [详细]
  • 2021最新总结网易/腾讯/CVTE/字节面经分享(附答案解析)
    本文分享作者在2021年面试网易、腾讯、CVTE和字节等大型互联网企业的经历和问题,包括稳定性设计、数据库优化、分布式锁的设计等内容。同时提供了大厂最新面试真题笔记,并附带答案解析。 ... [详细]
  • 生产环境下JVM调优参数的设置实例
     正文前先来一波福利推荐: 福利一:百万年薪架构师视频,该视频可以学到很多东西,是本人花钱买的VIP课程,学习消化了一年,为了支持一下女朋友公众号也方便大家学习,共享给大家。福利二 ... [详细]
author-avatar
xlenny
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有