【发布时间】: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 调试工具在应用程序遇到内存不足时捕获内存转储 - 然后找出 哪些 对象实际上正在泄漏。目前,听起来您在猜测,这绝不是解决此类问题的好方法(即,粗略阅读上面的代码看起来很合理,您可能没有向我们展示任何与实际泄漏相关的代码)
-
也许我遗漏了一些东西,但为什么将一堆字节写入文件会留下“很大的错误空间”?顺便说一句,监视标准输出应该适用于多个线程/进程。套接字也是如此,条件是您为每个进程提供唯一的端口号(例如,通过命令行参数)。您甚至可以使用更奇特的进程间通信通道,例如数据库或消息队列。