【问题标题】:Nasty memory leak when loading code in AppDomain在 AppDomain 中加载代码时出现严重的内存泄漏
【发布时间】:2012-02-28 23:12:50
【问题描述】:

我对我正在处理的一些代码有一个不寻常的要求。我正在使用不可靠的 3rd 方库进行一些条码扫描(运行太多次后它停止工作)。为了解决这个问题,我决定在单独的 AppDomain 中完成这项工作,然后在完成后卸载 AppDomain。这是对我正在做的事情的简单但准确的描述:

string domainID = Guid.NewGuid().ToString();
AppDomainSetup setup = new AppDomainSetup();
AppDomain domain = AppDomain.CreateDomain(domainID, null, setup);

string result = null;
try
{
    domain.SetData("stream", stream);
    domain.DoCallBack(ScanningContext.DoWork);

    result = domain.GetData("result") as string;
}
finally
{
    AppDomain.Unload(domain);
}

return result;

public static void DoWork()
{
    Stream s = AppDomain.CurrentDomain.GetData("stream") as Stream;
    ObjectHandle handle = AppDomain.CurrentDomain.CreateInstance("Scanning",
        "Scanner");

    Scanning.Scanner scanner = (Scanning.Scanner)handle.Unwrap();
    Scanning.Result[] results = scanner.Scan(s);

    AppDomain.CurrentDomain.SetData("result", results[0].Text);
}

“Scanner”是我正在使用的库的包装类。它位于“扫描”程序集中;一个单独的项目就是为了这个目的。

ScanningContext.DoWork 是我的服务程序集中的静态方法。

我对这种方法的问题是某些地方存在内存泄漏。内存不断增长(当然是在调用这段代码时),直到抛出 OutOfMemoryExceptions。

我在任何地方都找不到泄漏点。我所有的流都被处理掉了。我所有的字节数组都被清空了。我正在清理清单,过去对我有用的所有东西。我有 90% 的把握认为泄漏与 AppDomain 相关。这是我第一次使用它,所以我可能做错了什么。

我对 AppDomains 之外的另一种方法持开放态度。我确实需要能够从“扫描仪”类返回结果,因此不能选择生成进程。

【问题讨论】:

  • 您说您至少可以运行 3rd 方代码几次。那么,您能否通过使用应用程序域检查泄漏是否也存在来排除最后 10% 的不确定性?
  • 删除扫描器调用代码,返回一个固定的结果并检查内存泄漏是否仍然存在,那么它的appDomain问题,否则它的第3方库问题..
  • 老方法消耗内存很大,我现在看大约250,000k,所以它的内存使用不好。但是,它并没有像我的新方法那样耗尽内存。所以要回答你的问题,不,我不能排除其他 10%,我确实必须重写一些代码才能使用 AppDomains,所以我当时可以引入泄漏。
  • 使用 Windows 调试工具在应用程序遇到内存不足时捕获内存转储 - 然后找出 哪些 对象实际上正在泄漏。目前,听起来您在猜测,这绝不是解决此类问题的好方法(即,粗略阅读上面的代码看起来很合理,您可能没有向我们展示任何与实际泄漏相关的代码)
  • 也许我遗漏了一些东西,但为什么将一堆字节写入文件会留下“很大的错误空间”?顺便说一句,监视标准输出应该适用于多个线程/进程。套接字也是如此,条件是您为每个进程提供唯一的端口号(例如,通过命令行参数)。您甚至可以使用更奇特的进程间通信通道,例如数据库或消息队列。

标签: c# appdomain


【解决方案1】:

AppDomain.Unload 方法启动一个单独的线程来卸载域,这可能由于各种原因而失败(执行非托管代码的线程是一个问题)。以下是检查应用程序域是否已卸载的示例代码(取自 msdn 文档):

 try
 {
 Console.WriteLine();
 // Note that the following statement creates an exception because the domain no longer exists.
 Console.WriteLine("child domain: " + domain.FriendlyName);
 } 
 catch (AppDomainUnloadedException e)
 {
 Console.WriteLine("The appdomain MyDomain does not exist.");
 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-08
    • 1970-01-01
    • 2015-11-22
    • 1970-01-01
    • 1970-01-01
    • 2017-02-28
    • 2013-10-30
    相关资源
    最近更新 更多