.net 4.0 中的特性总结(三):垃圾回收
1.内存基础知识
- 每个进程都有其自己单独的虚拟地址空间。 同一台计算机上的所有进程共享相同的物理内存,如果有页文件,则也共享页文件。
- 默认情况下,32 位计算机上的每个进程都具有 2 GB 的用户模式虚拟地址空间。
- 作为一名应用程序开发人员,您只能使用虚拟地址空间,请勿直接操控物理内存。 垃圾回收器为您分配和释放托管堆上的虚拟内存。
- 如果您编写的是本机代码,请使用 Win32 函数处理虚拟地址空间。 这些函数为您分配和释放本机堆上的虚拟内存。
- 虚拟内存有三种状态:
可用。 该内存块没有引用关系,可用于分配。
保留。 内存块可供您使用,并且不能用于任何其他分配请求。 但是,在该内存块提交之前,您无法将数据存储到其中。
提交。 内存块已指派给物理存储。
- 可能会存在虚拟地址空间碎片。 就是说地址空间中存在一些被称为孔的可用块。 当请求虚拟内存分配时,虚拟内存管理器必须找到满足该分配请求的足够大的单个可用块。 即使您具有 2 GB 的可用空间,2 GB 的分配请求也有可能会不成功,除非所有这些空间必须位于单个的地址块中。
- 如果用完保留的虚拟地址空间或提交的物理空间,则可能会用尽内存。
2.垃圾回收的条件
当满足以下条件之一时将发生垃圾回收:
- 系统具有低的物理内存。
- 由托管堆上已分配的对象使用的内存超出了可接受的阈值。 这意味着可接受的内存使用的阈值已超过托管堆。 随着进程的运行,此阈值会不断地进行调整。
- 调用 GC.Collect 方法。 几乎在所有情况下,您都不必调用此方法,因为垃圾回收器会持续运行。 此方法主要用于特殊情况和测试
3.托管堆
在垃圾回收器由 CLR 初始化之后,它会分配一段内存用于存储和管理对象。 此内存称为托管堆(与操作系统中的本机堆相对)。
每个托管进程都有一个托管堆。 进程中的所有线程都在同一堆上分配对象。
当触发垃圾回收时,垃圾回收器将回收由死对象占用的内存。 回收进程会对活动对象进行压缩,以便将它们一起移动,并移除死空间,从而使堆更小一些。 这将确保一起分配的对象全都位于托管堆上,从而保留它们的局部性。
垃圾回收的侵入性(频率和持续时间)是由分配的数量和托管堆上保留的内存数量决定的。
此堆可视为两个堆的累计:大对象堆和小对象堆。
大对象堆包含其大小为 85,000 个字节和更多字节的对象。大对象堆上的特大对象通常是数组。 非常大的实例对象是很少见的。
4.代数
堆上的对象有三代:
- 第 0 代。 这是最年轻的代,其中包含短生存期对象。 短生存期对象的一个示例是临时变量。 垃圾回收最常发生在此代中。
- 新分配的对象构成新一代的对象并且为隐式的第 0 代回收,除非它们是大对象,在这种情况下,它们将进入第 2 代回收中的大对象堆。
- 大多数对象通过第 0 代中的垃圾回收进行回收,不会保留到下一代。
- 第 1 代。 这一代包含短生存期对象并用作短生存期对象和长生存期对象之间的缓冲区。
- 第 2 代。 这一代包含长生存期对象。 长生存期对象的一个示例是服务器应用程序中的一个包含在进程期间处于活动状态的静态数据的对象。
当条件得到满足时,垃圾回收将在特定代上发生。 回收某个代意味着回收此代中的对象及其所有更年轻的代。 第 2 代垃圾回收也称为完整垃圾回收,因为它回收所有代上的所有对象(即,托管堆中的所有对象)。
幸存和提升:垃圾回收中未回收的对象也称为幸存者,并会被提升到下一代。 在第 0 代垃圾回收中幸存的对象将被提升到第 1 代;在第 1 代垃圾回收中幸存的对象将被提升到第 2 代;而在第 2 代垃圾回收中幸存的对象将仍为第 2 代。
当垃圾回收器检测到某个代中的幸存率很高时,它会增加该代的分配阈值,因此下一次回收将会获取一个非常大的回收内存。 CLR 会在以下两个优先级别之前进行平衡:不允许应用程序的工作集获取太大内存以及不允许垃圾回收花费太多时间。
5.垃圾回收过程中发生的情况
垃圾回收分为以下几个阶段:
- 标记阶段,找到并创建所有活动对象的列表。
- 重定位阶段,用于更新对将要压缩的对象的引用。
- 压缩阶段,用于回收由死对象占用的空间,并压缩幸存的对象。 压缩阶段将垃圾回收中幸存下来的对象移至段中时间较早的一端。
因为第 2 代回收可以占用多个段,所以可以将已提升到第 2 代中的对象移动到时间较早的段中。 可以将第 1 代幸存者和第 2 代幸存者都移动到不同的段,因为它们已被提升到第 2 代。
将不会压缩大对象堆,因为这会在一个不可接受的时间长度内增加内存使用量。
垃圾回收器使用以下信息来确定对象是否为活动对象:
- 堆栈根。 由实时 (JIT) 编译器和堆栈查看器提供的堆栈变量。
- 垃圾回收句柄。 指向托管对象且可由用户代码或公共语言运行时分配的句柄。
- 静态数据。 应用程序域中可能引用其他对象的静态对象。 每个应用程序域都会跟踪其静态对象。
在垃圾回收启动之前,除了触发垃圾回收的线程以外的所有托管线程均会挂起。
下图演示了触发垃圾回收并导致其他线程挂起的线程。

6.后台垃圾回收
在后台垃圾回收中,在进行第 2 代回收的过程中,将会根据需要收集暂时代(第 0 代和第 1 代)。 后台垃圾回收无法设置;它会自动运行并启用并发垃圾回收。 后台垃圾回收是对并发垃圾回收的替代。 与并发垃圾回收一样,后台垃圾回收是在一个专用线程上执行的并且只适用于第 2 代回收。
后台垃圾回收期间对暂时代的回收称为前台垃圾回收。 发生前台垃圾回收时,所有托管线程都将被挂起。
当后台垃圾回收正在进行并且您已在第 0 代中分配了足够的对象时,CLR 将执行第 0 代或第 1 代前台垃圾回收。 专用的后台垃圾回收线程将在常见的安全点上进行检查以确定是否存在对前台垃圾回收的请求。 如果存在,则后台回收将挂起自身以便前台垃圾回收可以发生。 在前台垃圾回收完成之后,专用的后台垃圾回收线程和用户线程将继续。
后台垃圾回收可以消除并发垃圾回收所带来的分配限制,因为在后台垃圾回收期间,可发生暂时垃圾回收。 这意味着,后台垃圾回收可以移除暂时代中的死对象,而且还可以在第 1 代垃圾回收期间根据需要展开堆。
后台垃圾回收当前不可用于服务器垃圾回收
.net 4.0 中的特性总结(三):垃圾回收的更多相关文章
- Swift2.0 中的String(三):类型转换
本系列第三篇,String相关的类型转换.其他的几篇传送门(GitHub打不开链接的同学请自行把地址github改成gitcafe,或者直接去归档里找:-P): Swift2.0 中的String(一 ...
- javascript中的内存管理和垃圾回收
前面的话 不管什么程序语言,内存生命周期基本是一致的:首先,分配需要的内存:然后,使用分配到的内存:最后,释放其内存.而对于第三个步骤,何时释放内存及释放哪些变量的内存,则需要使用垃圾回收机制.本文将 ...
- (转载)JVM中的内存模型与垃圾回收
转载自微信公众号:Java高级架构(Java-jiagou)-----看完这篇文章,我奶奶都知道JVM中的内存模型与垃圾回收了! 六.内存模型 6.1 内存模型与运行时数据区 Java虚拟机在执行J ...
- C# 5.0中新增特性
C# 5.0随着VisualStudio 2012一起正式发布了,让我们来看看C#5.0中增加了哪些功能. 1. 异步编程 在.Net 4.5中,通过async和await两个关键字,引入了一种新的基 ...
- C#8.0中新特性之一:结构readonly成员
结构struct成员支持readonly,用来限制被其修饰的成员不会改变结构的内部状态.加上7.2版本添加的readonly struct和ref readonly方法返回以及之前的字段声明修饰作用, ...
- .net 4.0 中的特性总结(四):Tuple类型
Tuple是具有指定数量和顺序的值的一种数据结构.针对这种数据结构,.Net4.0中提供了一组Tuple类型,具体如下: Tuple Tuple<T> Tuple<T1, T ...
- C/C++中几种经典的垃圾回收算法
1.引用计数算法 引用计数(Reference Counting)算法是每个对象计算指向它的指针的数量,当有一个指针指向自己时计数值加1:当删除一个指向自己的指针时,计数值减1,如果计数值减为0,说明 ...
- 在Java中谈尾递归--尾递归和垃圾回收的比较(转载)
我不是故意在JAVA中谈尾递归的,因为在JAVA中谈尾递归真的是要绕好几个弯,只是我确实只有JAVA学得比较好,虽然确实C是在学校学过还考了90+,真学得没自学的JAVA好 不过也是因为要绕几个弯,所 ...
- Java中谈尾递归--尾递归和垃圾回收的比较
一.首先我们讲讲递归 1.递归的本质是,某个方法中调用了自身,本质还是调用了一个方法,只是这个方法正好是自身而已 2.递归因为是在自身中调用自身,所以会带来以下三个显著特点: 1.调用的是同一个 ...
随机推荐
- 【跑会指南】2017年3-5月IT技术会议大合集
2016年各类大会让人应接不暇,技术圈儿最不缺的就是各种大会小会,有的纯干货,有的纯广告.作为一名技术开发者,参加了几场大会,你是不是也开始思忖:究竟哪些会议才值得参加?下面活动家为你推荐几场2017 ...
- 【教程】发布NAServer到ArcGIS Server 10.4上[超详细]
前阵子对ArcGIS API For JavaScript的网络分析有兴趣,但是不知道其数据是如何获取的. 查阅API知道,AJS的网络分析只有三个功能:最短路径(RouteTask).最近设施点(C ...
- 【Netty】第一个Netty应用
一.前言 前面已经学习完了Java NIO的内容,接着来学习Netty,本篇将通过一个简单的应用来了解Netty的使用. 二.Netty应用 2.1 服务端客户端框架图 下图展示了Netty中服务端与 ...
- 解决mysql 服务无法启动问题:Can't find messagefile 'D:\ ools\mysql-5.6.25-winx64\share\errmsg.sys'
右击我的电脑-->管理,查看Window日志里的应用程序,发现报错. 仔细检查一下my.ini的配置,确保路径正确,楼主的目录如下: 关键的一步,查看my.default文件,加入这样一句:sq ...
- yii2 resetful 授权验证
什么是restful风格的api呢?我们之前有写过大篇的文章来介绍其概念以及基本操作. 既然写过了,那今天是要说点什么吗? 这篇文章主要针对实际场景中api的部署来写. 我们今天就来大大的侃侃那些年a ...
- 1-LPC1778建立工程
先来建立一个工程模板,,,要比32简单的多,假设32是用库开发的话,,,,因为还要把那些和库相关的文件加到工程里.... LPC呢就只需要把设置系统和总线的时钟文件(system_LPC177x_8x ...
- 高性能mysql(一)
1.连接和管理安全性 当客服端连接mysql服务器时,这个客户端就会在服务器端拥有一个线程,这个连接的查询就会在这单独的线程中执行.服务器会负责缓存线程,因此不需要为每一个连接都创建一个线程或者销毁一 ...
- Java中的栈上分配
博客搬家自https://my.oschina.net/itsyizu/blog/ 什么是栈上分配 栈上分配是java虚拟机提供的一种优化技术,基本思想是对于那些线程私有的对象(指的是不可能被其他线程 ...
- (one) 条件判断的总结
第一:if语句的一般形式: if(expression) statement1; statement2; 对于条件判断,我觉得要点在于“条件”(expression),它是一个结果为false或t ...
- repo版本切换
repo init -u https://android.googlesource.com/platform/manifest repo sync 之后 这样初始化之后,相当于下载了全部的分支, 本想 ...