.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 代垃圾回收期间根据需要展开堆。

后台垃圾回收当前不可用于服务器垃圾回收

时间: 2024-10-06 04:15:20

.net 4.0 中的特性总结(三):垃圾回收的相关文章

Java中的内存分配与垃圾回收

一.内存分配 Java程序运行时的内存分配,按照JVM规范,包括以下几个区域:程序计数器.虚拟机栈.本地方法栈.方法区.堆.其中,前三个是线程私有的,与线程生命周期相同,线程退出内存自动回收:后两者是所有线程共享内存的,只在垃圾回收机制被触发时,被动回收. * 程序计数器,内存区域极小,是当前线程的字节码执行行号指示器: * 虚拟机栈.本地方法栈,即平时所说的“栈”,是虚拟机用来执行方法(包括Java.非Java方法)时,使用的临时内存空间,用来存储当前方法.局部变量等,全部基本类型变量,以及类

.net 4.0 中的特性总结(一):dynamic

在新版本的C#中,dynamic关键词是一个很重要的新特性,现在你可以创建动态对象并在运行时再决定它的类型.而且.net 4.0为CLR加入了一组为动态语言服务的运行时环境,称为DLR(Dynamic Language Runtime动态语言运行时),这使得: C#这种静态类型语言可以在 .NET Framework 中开发动态语言并为与其它动态语言提供互操作性了. DLR架构见下图: 例如: 执行结果:

C# 6.0 的新特性

本文的内容包括引入C#6.0中的新的语言特性有哪些. 还有已经被引入的代码名称为 “Roslyn”新编译器. 编译器是开放源码的,并且可以从 codeplex 网站的这个地址下载到源代码: https://roslyn.codeplex.com/. C# 6.0 中的新特性 我们可以对这些新特性一个一个的进行讨论,而首先要列出 C# 6.0 中这些特性的一个清单 自动的属性初始化器 Auto Property Initializer 主构造器 Primary Consturctor 字典初始化器

探秘C# 6.0 的新特性

C# 6.0 中的新特性 我们可以对这些新特性一个一个的进行讨论,而首先要列出 C# 6.0 中这些特性的一个清单 自动的属性初始化器 Auto Property Initializer 主构造器 Primary Consturctor 字典初始化器 Dictionary Initializer 声明表达式 Declaration Expression 静态的Using Static Using catch 块中的 await 异常过滤器 Exception Filter 用于检查NULL值的条

Unity优化方向——优化Unity游戏中的垃圾回收

介绍 当我们的游戏运行时,它使用内存来存储数据.当不再需要该数据时,存储该数据的内存将被释放,以便可以重用.垃圾是用来存储数据但不再使用的内存的术语.垃圾回收是该内存再次可用以进行重用的进程的名称. Unity使用垃圾回收作为管理内存的一部分.如果垃圾回收发生得太频繁或者有太多工作要做,我们的游戏可能会表现不佳,这意味着垃圾回收是导致性能问题的常见原因. 在本文中,我们将了解垃圾回收如何工作的,什么时候发生垃圾回收,以及如何有效地使用内存,从而最小化垃圾回收对游戏的影响. 诊断垃圾回收的问题 垃

多线程二:jvm中的主线程&垃圾回收线程

1,什么时候使用多线程:当多个代码同事执行的时候就需要用到多线程. 2,jvm本身就是多线程的,因为在程序运行过程中会在堆内存产生很多垃圾,就需要被垃圾回收器进行回收. 3,main函数代码执行时,也在运行着垃圾回收.所以是同时执行的,这就是两个独立的线程来进行控制的. 4,执行垃圾回收的线程,称为垃圾回收线程. 5,执行main函数的线程,称为主线程. 6,创建一个执行路径(线程)的目的就是让单独一个线程去执行指定的代码和其他代码同事执行.这就是创建线程的目的. 7,对于主线程:它的运行代码度

在 .NET 4.0 中使用 .NET 4.5 中新增的特性(CallerMemberNameAttribute/CallerFilePathAttribute/CallerLineNumberAttribute)

介绍 标题中所说的三个特性 CallerMemberNameAttribute / CallerFilePathAttribute / CallerLineNumberAttribute 我们统称为调用者信息特性,正常情况下在 .NET Framework 4.0 中是无法使用的.因为这三个特性是 .NET Framework 4.5 中新增的.然而这三个特性的作用只是请求编译器在编译过程中进行代码的转换. 使用示例 static void Main( string[] args ) { var

VS2015 C#6.0 中的那些新特性

? VS2015 C#6.0 中的那些新特性 前言 ? ? ? VS2015在自己机器上确实是装好了,费了老劲了,想来体验一下跨平台的快感,结果被微软狠狠的来了一棒子了,装好了还是没什么用,应该还需要装Xarmain插件,配置一些参数吧,由于这块之前从未接触过,想了想还是先不把时间继续浪费在这里了,于是乎来体验一下新特性了. 本人个人博客原文链接地址为http://aehyok.com/Blog/Detail/66.html. ? ?本文参考http://roslyn.codeplex.com,

13、Cocos2dx 3.0游戏开发找小三之3.0中的Director :郝萌主,一统江湖

重开发人员的劳动成果.转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27706967 游戏中的基本元素 在曾经文章中.我们具体介绍了游戏开发的概念以及 Cocos2d-x 与其它游戏引擎的不同之处,甚至已经学会了它与众不同的 内存管理机制. 想必大家已经非常期待開始探索 Cocos2d-x 游戏开发的世界了. 在后面的文章中,我们将结合详细的实例,从 Cocos2d-x 游戏开发的基本元素讲起. 从这章開始,我会在学习引