基于代的垃圾回收机制--《CLR via C#》读书笔记
我们知道,垃圾回收在内存无限大的理想情况下是不需要的,正是因为内存存在的瓶颈,我们才需要垃圾回收。在《垃圾回收算法之引用计数算法》和《垃圾回收算法之引用跟踪算法》两篇文章中,我们了解了垃圾回收算法的基本原理,并介绍了两种垃圾回收算法。本篇是在垃圾回收的前提下,通过代的机制更进一步地提升程序的性能。
一.程序局部性原理
程序局部性原理是一种总结性的原理,它是指在程序执行时呈现局部性规律,即在一段时间内,整个程序的执行仅限于程序中的某一部分。相应地,执行所访问的存储空间也局限于某个内存区域。
这个局部性原理有两层含义:一层是时间局部性,如果一个变量正在被访问,那么它近期很有可能被再次访问;一层是空间局部性,马上要使用的信息与正在使用的信息在空间地址上是临近的。
通俗地讲:对象越新,生存期越短,对象越老,生存期越长。
二.代
C#的GC把托管堆分为3代,依次为G0、G1、G2,G0总是用来分配新对象,垃圾回收中G0幸存的对象放到对象生存期更长的G1中,在下一次的回收G1中垃圾后,G1中垃圾的对象放到对象生存期更长的G2中;CLR初始化时会为G0、G1、G2分配空间预算,每一代的垃圾回收只有在本代的空间预算用完后才会启动垃圾回收。
下面,我们通过《CLR via C#》中的例子来理解代的运行机制:
在托管堆初始化时不包含对象,添加到堆中的对象称为0代对象。
在step1中,G0中新进了3个对象,过了一会了,对象c变得不可达了,现在我要分配一个新的对象d、e、f,这时G0超过了预算了。
前面我们说过,G0总是用来分配新对象,因此虽然这时G1和G2空间是足够的,但也不能用来分配给新对象;另外,前面我们也说过,每一代的垃圾回收只有在本代的 空间预算用完后才会启动垃圾回收。
因此,我们需要启动G0的垃圾回收,将c回收掉,将a、b幸存,并升级到G1中,经过第1次的垃圾回收后如下:
回收后的G0是空的,正好可以用来分配新进的d、e、f,如下所示:
过了一段时间后,f变成可达了,现在我们要分配新的对象g、h、i,发现G0被占满了,于是回收G0(注意这时不回收G1,因为G1的空间预算还没有用完),并将d和e加入G1,经过这次的回收后如下图所示:
回收后的G0又变空了,可以容纳新的对象,如下所示:
现在,我们要分配新的对象,j、k、l,这时发现G0和G1的空间预算都用完了,于是回收G0和G1,并将G1中幸存的对象升至G2,G0中幸存的对象升至G1,经过这次的回收后如下图所示:
回收过后的G0又变空了,可以容纳新的对象j、k、l。依此往复。如果没有回收到足够多的内存时,垃圾回收器就会执行一次完整的垃圾回收,如果还是不够,就抛出OutOfMemoryException异常。
三.程序局部性原理在代机制中的应用
前面,我们谈到了程序局部性原理,其中说对象越新生存期越短,具体到代机制中,G0总是存着最新的对象,因此G0中包含垃圾的可能性也就更大,能回收更多的内存,对于G0的回收也更频繁。
同理,对于G1的回收就没有那么频繁了,因为根据程序局部性原理,G1中的对象活得更长,在回收G0且G1的内存没有超出预算时,如果也去回收G1中的垃圾,有可能找不出多少垃圾,因此对G1的垃圾回收有可能是浪费时间。
也就是说G0回收时,如果G1没有超出预算,是不会回收G1的,如果G1有垃圾,它将留在G1当中,,这样就加快了回收的速度。
四.另一个提升性能的重要因素:不必遍历所有根
另一个提升性能的重要因素,在于我们不必遍历所有的根,如果根或对象引用了老一代的对象,垃圾回收器就可以忽略老对象内部的所有引用,能更快地构建对象可达图。
但问题来了,如果老对象在原来的程序中是不可达的,在G0引入新对象后,又引用了新对象呢?那如何更新老对象的引用呢?
垃圾回收器利用了JIT编译器内部的一个机制,在对象的引用字段发生变化时,会设置一个相应的位标志,这样垃圾回收器就知道自上一次垃圾回收以来,哪些老对象已被写入,只有字段发生变化的老对象才需要是否引用了G0中的任何新对象。
五.大对象
到目前为止,前面我们说的都是小对象,CLR认为超过85000字节的即是大对象。针对大对象:
- 大对象不在小对象的地址空间分配,而在进程地址空间的其他地方分配
- 目前,GC不压缩,因为在内存中移动它代价太高,但这可能造成大对象之间造成碎片化
- 大对象总是G2,所以只能为需要长时间存活的资源创建大对象,分配短时间存活的大对象会导致G2被频繁地回收,会损害性能。
六.内存预算的调节—自调节
垃圾回收器会在执行垃圾回收的过程中了解应用程序的行为,同时根据行为来动态调整G0、G1、G2的预算。
假如应用程序构建了相当多的短时间使用的对象,造成G0的垃圾回收会回收大量内存,就可能减少G0的预算,这样G0的回收将更加频繁,但垃圾回收器每次做的事情也就更少了,这减少了进程的工作集。如果G0中全是垃圾,则不需要经过压缩内存,直接让NextObjPrj指针指回G0的开始处即可。这样回收起来更快!
假如垃圾回收器在回收G0时发现还有很多对象存活,就会增大G0的预算,垃圾的回收次数将减少,但每次垃圾回收时,回收的内存就会多得多。
参考
《CLR via C#》(第4版)
基于代的垃圾回收机制--《CLR via C#》读书笔记的更多相关文章
- 垃圾回收算法简单介绍——JVM读书笔记<二>
垃圾回收的过程主要包含两部分:找出已死去的对象.移除已死去的对象. 确定哪些对象存活有两种方式:引用计数算法.可达性分析算法. 方案一:引用计数算法 给对象中加入一个引用计数器.每当有一个地方引用它时 ...
- CLR via C# 读书笔记-21.托管堆和垃圾回收
前言 近段时间工作需要用到了这块知识,遂加急补了一下基础,CLR中这一章节反复看了好多遍,得知一二,便记录下来,给自己做一个学习记录,也希望不对地方能够得到补充指点. 1,.托管代码和非托管代码的区别 ...
- [转载收藏]C#基础知识梳理系列十一:垃圾回收机制
摘 要 基于.NET平台的开发语言中,最让开发人员爽的一点就是垃圾回收处理机制,在编码过程中,终于可以解放你的双手来关注更重要的事情.很多的资料中在讲到.NET中的垃圾回收机制时都说"CLR ...
- Python垃圾回收机制--完美讲解!
转自: http://www.jianshu.com/p/1e375fb40506 先来个概述,第二部分的画述才是厉害的. Garbage collection(GC) 现在的高级语言如java,c# ...
- python垃圾回收机制(Garbage collection)
由于面试中遇到了垃圾回收的问题,转载学习和总结这个问题. 在C/C++中采用用户自己管理维护内存的方式.自己管理内存极其自由,可以任意申请内存,但也为大量内存泄露.悬空指针等bug埋下隐患. 因此在现 ...
- 浅谈 JavaScript 垃圾回收机制
github 获取更多资源 https://github.com/ChenMingK/WebKnowledges-Notes 在线阅读:https://www.kancloud.cn/chenmk/w ...
- Python的内存管理和垃圾回收机制
内存管理 Python解释器由c语言开发完成,py中所有的操作最终都由底层的c语言来实现并完成,所以想要了解底层内存管理需要结合python源码来进行解释. 1. 两个重要的结构体 include/o ...
- 成为JavaGC专家(1)—深入浅出Java垃圾回收机制
转载自:http://www.importnew.com/1993.html 对于Java开发人员来说,了解垃圾回收机制(GC)有哪些好处呢?首先可以满足作为一名软件工程师的求知欲,其次,深入了解GC ...
- 转:成为JavaGC专家Part I — 深入浅出Java垃圾回收机制
文章来自于:http://www.importnew.com/1993.html 对于Java开发人员来说,了解垃圾回收机制(GC)有哪些好处呢?首先可以满足作为一名软件工程师的求知欲,其次,深入了解 ...
随机推荐
- 单元测试,模拟用户Get登陆,并携带登录后的token访问接口
HttpClient _httpClient; HttpClient _businessHttpClient; private async Task<string> GetAccessTo ...
- oracle EBS rtf报表不能输出模板样式
1.需要定义中文的数据定义 2.缺少文件 cd $ADMIN_SCRIPTS_HOME prefs.ora 3.查看文档 文档 ID 1059712.1 (1)请求模版显示不出来 解决:模版定义中模 ...
- mysql中InnoDB表为什么要建议用自增列做主键
InnoDB引擎表的特点 1.InnoDB引擎表是基于B+树的索引组织表(IOT) 关于B+树 (图片来源于网上) B+ 树的特点: (1)所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关 ...
- Unity By Reflection Update Scripts
App热更新需求 我正在使用Unity 3D开发一个Android的应用,它会下载AssetBundles并加载它们的内容,但由于AssetBundles不能包含脚本,我将使用预编译的C#脚本,并使用 ...
- python的学习之路day6
大纲: 1.反射 其中的方法:getattr,delattr,setattr,hasattr __import__() __import__() 注意事项 2.模块中的特殊变量 __doc__ __c ...
- October 22nd, 2017 Week 43rd Sunday
Yesterday is not ours to recover, but tomorrwo is ours to win or lose. 我们无法重拾昨天,但我们可以选择赢得或者输掉明天. Eve ...
- sdn2017 第三次作业
1.阅读: 阅读<图解openflow>第一二章(请自己查找相应书籍) 阅读文章:http://www.sdnlab.com/19777.html 阅读<重构网络>第一二章 2 ...
- libcurl.dll 7.60.0静态库包含openssl/zlib
最近做个QT的小程序需要使用LIBCURL支持HTTPS,结果查资料发现官方默认的是不支持的,需要手动重新编译,编译的时候加入SSL支持. 看着就好麻烦的样子, 找了一圈,还真有现成的,但是现在写程序 ...
- [python]如何理解uiautomator里面的 right,left,up,down 及使用场景
关于Android自动化uiautomator 框架,前面有讲在有些场景下,比如需要在设置界面中将某些选项开关打开或者关闭(前提是这些选项和开关的控件(resourceId,className,tex ...
- 【转】jquery cookie操作
Cookie是网站设计者放置在客户端的小文本文件.Cookie能为用户提供很多的使得,例如购物网站存储用户曾经浏览过的产品列表,或者门户网站记住用户喜欢选择浏览哪类新闻. 在用户允许的情况下,还可以存 ...