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

1.内存基础知识数组

  • 每一个进程都有其本身单独的虚拟地址空间。 同一台计算机上的全部进程共享相同的物理内存,若是有页文件,则也共享页文件。
  • 默认状况下,32 位计算机上的每一个进程都具备 2 GB 的用户模式虚拟地址空间。
  • 做为一名应用程序开发人员,您只能使用虚拟地址空间,请勿直接操控物理内存。 垃圾回收器为您分配和释放托管堆上的虚拟内存。
  • 若是您编写的是本机代码,请使用 Win32 函数处理虚拟地址空间。 这些函数为您分配和释放本机堆上的虚拟内存。
  • 虚拟内存有三种状态:

        可用。 该内存块没有引用关系,可用于分配。安全

        保留。 内存块可供您使用,而且不能用于任何其余分配请求。 可是,在该内存块提交以前,您没法将数据存储到其中。服务器

         提交。 内存块已指派给物理存储。并发

  • 可能会存在虚拟地址空间碎片。 就是说地址空间中存在一些被称为孔的可用块。 当请求虚拟内存分配时,虚拟内存管理器必须找到知足该分配请求的足够大的单个可用块。 即便您具备 2 GB 的可用空间,2 GB 的分配请求也有可能会不成功,除非全部这些空间必须位于单个的地址块中。
  • 若是用完保留的虚拟地址空间或提交的物理空间,则可能会用尽内存。

2.垃圾回收的条件函数

当知足如下条件之一时将发生垃圾回收:测试

  • 系统具备低的物理内存。
  • 由托管堆上已分配的对象使用的内存超出了可接受的阈值。 这意味着可接受的内存使用的阈值已超过托管堆。 随着进程的运行,此阈值会不断地进行调整。
  • 调用 GC.Collect 方法。 几乎在全部状况下,您都没必要调用此方法,由于垃圾回收器会持续运行。 此方法主要用于特殊状况和测试

3.托管堆spa

在垃圾回收器由 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) 编译器和堆栈查看器提供的堆栈变量。
  • 垃圾回收句柄。 指向托管对象且可由用户代码或公共语言运行时分配的句柄。
  • 静态数据。 应用程序域中可能引用其余对象的静态对象。 每一个应用程序域都会跟踪其静态对象。

在垃圾回收启动以前,除了触发垃圾回收的线程之外的全部托管线程均会挂起。

下图演示了触发垃圾回收并致使其余线程挂起的线程。

image

6.后台垃圾回收

在后台垃圾回收中,在进行第 2 代回收的过程当中,将会根据须要收集暂时代(第 0 代和第 1 代)。 后台垃圾回收没法设置;它会自动运行并启用并发垃圾回收。 后台垃圾回收是对并发垃圾回收的替代。 与并发垃圾回收同样,后台垃圾回收是在一个专用线程上执行的而且只适用于第 2 代回收。

后台垃圾回收期间对暂时代的回收称为前台垃圾回收。 发生前台垃圾回收时,全部托管线程都将被挂起。

当后台垃圾回收正在进行而且您已在第 0 代中分配了足够的对象时,CLR 将执行第 0 代或第 1 代前台垃圾回收。 专用的后台垃圾回收线程将在常见的安全点上进行检查以肯定是否存在对前台垃圾回收的请求。 若是存在,则后台回收将挂起自身以便前台垃圾回收能够发生。 在前台垃圾回收完成以后,专用的后台垃圾回收线程和用户线程将继续。

后台垃圾回收能够消除并发垃圾回收所带来的分配限制,由于在后台垃圾回收期间,可发生暂时垃圾回收。 这意味着,后台垃圾回收能够移除暂时代中的死对象,并且还能够在第 1 代垃圾回收期间根据须要展开堆。

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

相关文章
相关标签/搜索