.NET中的垃圾收集器

时间:2012-04-04 05:55:03

标签: asp.net .net c#-4.0 garbage-collection

垃圾收集器如何知道对象和变量超出范围,以便垃圾收集器可以收集它们?

4 个答案:

答案 0 :(得分:6)

简而言之:每个应用程序都有一组根。 Roots标识存储位置,这些位置引用托管堆上的对象或设置为null的对象。

当垃圾收集器开始运行时,它会假设堆中的所有对象都是垃圾。

垃圾收集器开始遍历根并构建可从根访问的所有对象的图形。

删除所有无法访问的对象(释放内存)

这取自http://msdn.microsoft.com/en-us/magazine/bb985010.aspx - 关于垃圾收集的好文章。 “有趣”的部分是“垃圾收集算法”。这不是一个很长的部分

答案 1 :(得分:3)

如果不参考Raymond Chen出色的博客文章系列,那么在.NET中没有关于垃圾收集的讨论是完整的:

以下是本系列第一篇文章的引用:

  

当你问某人垃圾收集是什么时,你得到的答案可能就是“垃圾收集就是当操作环境自动回收程序不再使用的内存时。”它会这样做通过跟踪从根开始的内存来识别哪些对象是可访问的。“

     

此描述将机制与目标混淆。这就像是说消防员的工作是“驾驶一辆红色卡车并喷水”。这是对消防员做什么的描述,但它忽略了工作的重点(即灭火,更普遍的是消防安全)。

以下是他演示的一些有趣的观点:

  

正确编写的程序不能假定终结器将会运行。

  

在执行名为的函数期间,代码块中的对象可以符合集合的条件。

  

当方法仍在执行时,方法的参数可以符合收集的条件。

  

一个奇怪的现实世界类比:垃圾收集器可以在潜水员最后一次接触潜水板时收集 - 即使潜水员还在空中!

而且,最简洁:

  

不要认为GC是追根溯源。将GC视为删除不再使用的内容。

答案 2 :(得分:0)

垃圾收集器(GC)是.NET框架的一部分,该框架由公共语言运行时(CLR)初始化以管理分配和发布应用程序中的内存数量。

垃圾收集器的类型

垃圾收集器可以在多种情况下工作。 CLR提供以下类型的垃圾收集:

  • 工作站垃圾回收(GC)以正常优先级运行 线程,可以是并发的或非并发的,并且设计用于 客户端应用
  • 服务器垃圾收集旨在用于服务器应用程序和 创建一个单独的托管堆和相应的垃圾 每个逻辑CPU的收集线程。线程在最高处运行 优先级使其速度更快,但资源更加密集。在.NET Core中, .NET Framework 4.5和更高版本的服务器垃圾收集可以 是非并发的或背景的。在.NET Framework 4及更高版本中 版本中,服务器垃圾回收是非并行的。

并发垃圾收集 并发垃圾回收允许用户线程为第二代垃圾回收的大部分运行。只要托管堆中仍有可用空间供新分配,用户线程就可以运行并创建新对象。

enter image description here

非并发垃圾收集 非并发垃圾收集会在垃圾收集的整个过程中暂停所有非垃圾收集线程,从而在该时间内有效地暂停了应用程序。

背景垃圾收集 后台垃圾回收是并发垃圾回收的替代。它与并发垃圾回收类似,但是允许第0代和第1代垃圾回收中断正在进行的第2代垃圾回收并暂时阻止程序执行。在完成了第0代和第1代垃圾回收之后,继续执行程序以及第2代垃圾回收。这甚至进一步缩短了由于垃圾回收而暂停程序执行的时间。

内存和托管堆 一旦公共语言运行库(CLR)初始化了垃圾收集器,垃圾收集器就会分配一个称为托管堆(与操作系统中的本机堆相对)的内存段,以存储和管理对象。 >

对于每个托管进程,垃圾收集器使用Windows VirtualAlloc 函数在托管堆中保留一部分内存。 (它使用Windows VirtualFree 功能将段释放回操作系统)。进程中的所有线程都为同一堆上的对象分配内存。

要考虑的重要一件事是,每个分配的段的大小都是特定于实现的,并且随时可能更改。

世代

存储在托管堆中的对象根据其年龄进行组织。垃圾收集主要是通过回收通常仅占堆很小一部分的短期对象来进行的。

  • 第0代:具有短命对象的最年轻一代(例如 临时变量或新分配的对象,除非它们很大 对象,在这种情况下,它们会放在一个大对象堆中 第二代收藏)
  • 第1代:如果某个第0代对象占用的空间 没有在垃圾回收运行中释放,则这些对象得到 移至第1代,并包含寿命短的对象。
  • 第二代。如果某个第一代对象占用的空间是 没有在下一次垃圾回收运行中释放,则这些对象 移到第二代。这一代包含了很长的生命 对象(即服务器应用程序中包含静态对象的对象 整个过程中一直存在的数据)。

当垃圾收集器检测到某代的生存率很高时,它将增加该代的分配阈值。

垃圾收集器阶段

该收集是由以下条件之一触发的:

  • 系统的物理内存不足。可以通过 来自操作系统的内存不足通知或内存不足,如 主机。

  • 托管堆上分配的对象使用的内存 超过可接受的阈值。此阈值是连续的 在过程运行时进行调整。

  • 将调用GC.Collect方法。在几乎所有情况下,您都没有 之所以调用此方法,是因为垃圾收集器连续运行。

此时,垃圾收集器传递将引发以下阶段:

  1. 标记阶段:GC创建所有活动对象(所有 不在列表上的对象可能会被删除) 使用以下信息确定对象是否为 是否生活:

    • 堆栈根。。即时(JIT)编译器和堆栈行程序提供的堆栈变量。 JIT优化可以延长或缩短将堆栈变量报告给垃圾收集器的代码区域。
    • 垃圾收集句柄。指向托管对象的句柄,可以由用户代码或公共语言运行时分配。
    • 静态数据。应用程序域中的静态对象可能正在引用其他对象。每个应用程序域都跟踪其静态对象。
  2. 重定位阶段:所有动态对象列表中所有对象的引用在重定位阶段中进行了更新,以便它们指向对象将要位于的新位置在压实阶段重新定位。 压实阶段:回收死物占据的空间并压实尚存的物体。压缩阶段将在垃圾回收后幸存下来的对象移到该段的较旧端。随着释放死对象占用的空间并移动剩余的活动对象,堆会在压缩阶段被压缩。垃圾回收后剩余的所有活动对象均按其原始顺序移至堆内存的较早一端

资源

官方文档https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals

答案 3 :(得分:-4)

请浏览http://msdn.microsoft.com/en-us/magazine/bb985010.aspx。 正如它所说的

垃圾收集器检查堆中是否有任何对象不再被应用程序使用。如果存在此类对象,则可以回收这些对象使用的内存。