垃圾收集是在进程级别还是 appdomain 级别发生的?

Posted

技术标签:

【中文标题】垃圾收集是在进程级别还是 appdomain 级别发生的?【英文标题】:Does garbage collection happen at the process level or appdomain level? 【发布时间】:2013-03-06 11:29:07 【问题描述】:

FullGC 通常会在运行时暂停所有线程。有两个 AppDomain,每个都运行多个线程。当 GC 运行时,是暂停所有线程,还是只暂停其中一个 AppDomain 的线程?

【问题讨论】:

【参考方案1】:

很难回答,最好的办法就是测试一下:

using System;
using System.Reflection;

public class Program : MarshalByRefObject 
    static void Main(string[] args) 
        var dummy1 = new object();
        var dom = AppDomain.CreateDomain("test");
        var obj = (Program)dom.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().FullName, typeof(Program).FullName);
        obj.Test();
        Console.WriteLine("Primary appdomain, collection count = 0, gen = 1",
            GC.CollectionCount(0), GC.GetGeneration(dummy1));
        Console.ReadKey();

    
    public void Test() 
        var dummy2 = new object();
        for (int test = 0; test < 3; ++test) 
            GC.Collect();
            GC.WaitForPendingFinalizers();
         
        Console.WriteLine("In appdomain '0', collection count = 1, gen = 2",
            AppDomain.CurrentDomain.FriendlyName, GC.CollectionCount(0),
            GC.GetGeneration(dummy2));
    

输出:

In appdomain 'test', collection count = 3, gen = 2
Primary appdomain, collection count = 3, gen = 2

很好的证据表明 GC 会影响默认 CLR 主机上的所有 AppDomain。这让我很吃惊。

【讨论】:

您确定每个 AppDomain 都有自己的堆吗?这与 Brian Rasmussen 的回答相矛盾:***.com/questions/574708/what-is-appdomain 和 Aghilas Yakoub 的回答:***.com/questions/12219815/appdomains-and-gc-heap “AppDomain 是同一进程的一部分,因此实际上共享同一个托管堆”。这和你说的不矛盾吗?另请参阅我对我的评论的编辑,Aghilas 说“您有一个进程堆,并且应用程序域共享这个堆。”除非我有误解,否则似乎至少有一个答案(您的或他们的)需要更正。 好吧,我会缓和一点。它们在逻辑上是不同的,因为对象句柄指向 AppDomain 特定的数据结构。因此需要跨域编组。但是测试中确实有证据表明 GC 堆本身是共享的。 @TimGoodman 请注意,.NET 同时管理许多不同的托管堆,即使在同一个AppDomain 中也是如此。这在使用服务器 GC 时尤其明显,其中每个线程都可以拥有自己的堆。但是,GC 仍然必须遍历所有这些,因为它们可以有交叉引用。【参考方案2】:

从这里的线程:Is the garbage collector in .net system-wide or application-wide?,它发生在进程级别。该进程中的所有线程都将暂停,但不会跨多个进程。

一个或多个应用程序域可以存在于一个进程中,但应用程序域不能在进程之间共享。 Per:http://blogs.msdn.com/b/tess/archive/2008/08/19/questions-on-application-domains-application-pools-and-unhandled-exceptions.aspx,“进程中的所有 appdomains 共享同一个 GC。”因此,GC 应该会在触发 GC 时影响所有应用程序域。

但是,过多的进程花费时间执行 GC 可能会影响 CPU 性能,这可能会对未参与 GC 的其他进程的性能产生负面影响。

这个链接也解释了 GC 的基本原理:

http://msdn.microsoft.com/en-us/library/ee787088.aspx

【讨论】:

以上是关于垃圾收集是在进程级别还是 appdomain 级别发生的?的主要内容,如果未能解决你的问题,请参考以下文章

跨 AppDomain 边界的垃圾收集对象

寻找垃圾收集根[关闭]

页面加载后对象是不是有资格进行垃圾收集?

IIS - 应用程序池之间共享的垃圾收集?

多个 .NET AppDomain 的代码示例

Linux常用性能工具功能用法及原理