外部进程的垃圾回收

7
有没有可能强制对外部进程进行垃圾回收? 我的意思是不需要附加到Visual Studio / windbg等。 我知道可以使用类似VS Immediate窗口的东西来执行此操作。
编辑:看起来可以通过PerfView完成此操作,但我无法找到太多信息,例如是否进行了完整的GC等。 有什么想法吗?

你为什么还想要这样做? - Lasse V. Karlsen
我没有进行贬值,但如果您查看按钮的文本,它会说“这个问题没有展示任何研究努力;它不清楚或无用”。在您被贬值时,您没有展示出任何研究努力,这很可能是为什么会被贬值的原因。 - Scott Chamberlain
3个回答

15

从外部进程强制进行垃圾收集的选项有:

1)使用调试器API连接并调用GC.Collect()方法。我最初尝试使用PerfView进行此操作,但如果进程在本地代码中被阻止(调试器直到再次运行托管代码才会附加),则无法正常工作,这是不可接受的。

2)注入分析器(自V4.5以来可以通过附加操作完成)并调用其中的API来执行GC。这确实有效(假设没有其他分析器已经附加)。事实上,这就是PerfView所做的。

3)使用Windows事件跟踪(ETW)。自运行时的V4.5以来,有一个称为GCHeapCollect的关键字,如果设置了它将导致运行时执行完全GC。您需要成为管理员才能启用ETW提供程序,因此仅当您的“控制”进程可以成为管理员时才有效。如果要执行此操作,请使用TraceEvent Nuget包(请参见http://blogs.msdn.com/b/vancem/archive/2014/03/15/walk-through-getting-started-with-etw-traceevent-nuget-samples-package.aspx)。通常,ETW会向系统上的所有进程发送请求,但您可以使用TraceEventProviderOptions将其定位到特定进程(在Win 8或更高版本上)。

请注意,这些选项均不适用于普通用途。你应该成为像调试器或分析器这样的角色才能进行此类操作。在没有参与的情况下强制其他进程进行GC通常是不好的……

Vance Morrison .NET性能架构师。


感谢 Vance 提供非常有用的技巧。 - crazy novice
谢谢 Vance。我已经按照你的ETW建议实现了下面的代码,虽然我对ETW或库知之甚少。如果您能检查一下是否存在明显的问题或改进,那就太好了。 - Taran

3
如果有人正在寻找使用ETW进行此操作的代码(如@Vance Morrison所建议的),则以下是我使用Microsoft.Diagnostics.Tracing.TraceEvent nuget包并调整提供的示例所想出的内容。
注意可能有更好/更简单的方法来完成它,但对于我的用例,它始终可以一致地正常工作。
请将替换为您的进程ID整数。
using (var userSession = new TraceEventSession("TriggerGC"))
{
    userSession.EnableProvider(
        ClrTraceEventParser.ProviderGuid, 
        TraceEventLevel.Verbose, 
        (ulong)(ClrTraceEventParser.Keywords.GCHeapCollect), new TraceEventProviderOptions
        {
            ProcessIDFilter = new List<int>() { <PROCESS_ID> }
        });

    userSession.Source.StopProcessing();    
}

2
+1:感谢提供宝贵的信息。我已经创建了一个版本,还报告了有关集合进度和状态的一些信息这里 - Christian.K

2

不,无论是Windows还是.NET都没有提供任何API可以在不附加调试器的情况下强制对外部进程进行GC。

您必须附加调试器并使用该路线来强制GC。


@PaulSnow PerfView 要么临时附加调试器,强制进行垃圾回收,然后分离;要么在整个过程中一直附加调试器。你说你不想在你的解决方案中这样做。 - Scott Chamberlain
你说得对,我可能在我的问题表述上不够清晰。我发现有些人建议安装VS并从其立即窗口执行GC.Collect。这听起来像是一个非常繁重的解决方案(需要安装VS)。所以我基本上不想使用那个方法。 - crazy novice
1
如果您想编写一个程序来执行它,那么您需要编写与 DebuggingAPI 进行交互的代码,这不是一件容易的事情(因为这涉及到许多非托管 COM 调用,我不建议将其作为您的第一个 COM 互操作项目)。您可以尝试创建一个命令行程序来封装接口,如 MDbg,然后从您的程序中调用它并传递相应的命令。 - Scott Chamberlain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接