- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
背景
我有一个 Windows 服务,它使用各种第三方 DLL 来处理 PDF 文件。这些操作会占用相当多的系统资源,并且在发生错误时偶尔会出现内存泄漏。 DLL 是其他非托管 DLL 的托管包装器。
当前解决方案
在一种情况下,我已经通过在专用控制台应用程序中包装对其中一个 DLL 的调用并通过 Process.Start() 调用该应用程序来缓解此问题。如果操作失败并且存在内存泄漏或未释放的文件句柄,则无关紧要。该过程将结束,操作系统将恢复句柄。
我想将同样的逻辑应用到我的应用程序中使用这些 DLL 的其他地方。但是,我对在我的解决方案中添加更多控制台项目并编写更多样板代码来调用 Process.Start() 并解析控制台应用程序的输出并不感到非常兴奋。
新解决方案
专用控制台应用程序和 Process.Start() 的一个优雅替代方案似乎是使用 AppDomains,如下所示:http://blogs.geekdojo.net/richard/archive/2003/12/10/428.aspx .
我已经在我的应用程序中实现了类似的代码,但单元测试并不乐观。我在单独的 AppDomain 中为测试文件创建了一个 FileStream,但不处理它。然后我尝试在主域中创建另一个 FileStream,但由于未释放的文件锁定而失败。
有趣的是,向工作域添加一个空的 DomainUnload 事件会使单元测试通过。无论如何,我担心创建“worker”AppDomains 可能无法解决我的问题。
想法?
代码
/// <summary>
/// Executes a method in a separate AppDomain. This should serve as a simple replacement
/// of running code in a separate process via a console app.
/// </summary>
public T RunInAppDomain<T>( Func<T> func )
{
AppDomain domain = AppDomain.CreateDomain ( "Delegate Executor " + func.GetHashCode (), null,
new AppDomainSetup { ApplicationBase = Environment.CurrentDirectory } );
domain.DomainUnload += ( sender, e ) =>
{
// this empty event handler fixes the unit test, but I don't know why
};
try
{
domain.DoCallBack ( new AppDomainDelegateWrapper ( domain, func ).Invoke );
return (T)domain.GetData ( "result" );
}
finally
{
AppDomain.Unload ( domain );
}
}
public void RunInAppDomain( Action func )
{
RunInAppDomain ( () => { func (); return 0; } );
}
/// <summary>
/// Provides a serializable wrapper around a delegate.
/// </summary>
[Serializable]
private class AppDomainDelegateWrapper : MarshalByRefObject
{
private readonly AppDomain _domain;
private readonly Delegate _delegate;
public AppDomainDelegateWrapper( AppDomain domain, Delegate func )
{
_domain = domain;
_delegate = func;
}
public void Invoke()
{
_domain.SetData ( "result", _delegate.DynamicInvoke () );
}
}
[Test]
public void RunInAppDomainCleanupCheck()
{
const string path = @"../../Output/appdomain-hanging-file.txt";
using( var file = File.CreateText ( path ) )
{
file.WriteLine( "test" );
}
// verify that file handles that aren't closed in an AppDomain-wrapped call are cleaned up after the call returns
Portal.ProcessService.RunInAppDomain ( () =>
{
// open a test file, but don't release it. The handle should be released when the AppDomain is unloaded
new FileStream ( path, FileMode.Open, FileAccess.ReadWrite, FileShare.None );
} );
// sleeping for a while doesn't make a difference
//Thread.Sleep ( 10000 );
// creating a new FileStream will fail if the DomainUnload event is not bound
using( var file = new FileStream ( path, FileMode.Open, FileAccess.ReadWrite, FileShare.None ) )
{
}
}
最佳答案
应用程序域和跨域交互是一件非常简单的事情,所以在做任何事情之前,应该确保他真的了解事情是如何工作的......嗯......让我们说,“非标准”:-)
首先,您的流创建方法实际上是在您的“默认”域上执行的(出乎意料!)。为什么?简单:您传入的方法 AppDomain.DoCallBack
在 AppDomainDelegateWrapper
上定义对象,并且该对象存在于您的默认域中,因此这是执行其方法的地方。 MSDN 没有提到这个小“功能”,但检查起来很容易:只需在 AppDomainDelegateWrapper.Invoke
中设置一个断点即可。 .
因此,基本上,您必须在没有“包装器”对象的情况下凑合。对 DoCallBack 的参数使用静态方法。
但是您如何将您的“func”参数传递到另一个域,以便您的静态方法可以选择并执行它?
最明显的方法是使用AppDomain.SetData
, 或者你可以推出你自己的,但不管你怎么做,还有另一个问题:如果“func”是一个非静态方法,那么它定义的对象必须以某种方式传递到另一个应用程序域。它可以通过值(而它被逐个字段地复制)或通过引用(创建具有远程处理的所有美感的跨域对象引用)传递。要做到前者,必须用 [Serializable]
标记该类。属性。要做到后者,它必须继承自 MarshalByRefObject
.如果该类都不是,则在尝试将对象传递给另一个域时将引发异常。但是请记住,通过引用传递几乎会扼杀整个想法,因为您的方法仍将在对象所在的同一域上调用 - 即默认域。
结束上面的段落,您有两个选择:要么传递在标有 [Serializable]
的类上定义的方法。属性(并记住对象将被复制),或者传递一个静态方法。我怀疑,为了您的目的,您将需要前者。
以防万一它没有引起您的注意,我想指出您的第二次过载 RunInAppDomain
(采用 Action
的方法)传递定义在未标记为 [Serializable]
的类上的方法.没有看到那里有任何类(class)吗?您不必:使用包含绑定(bind)变量的匿名委托(delegate),编译器将为您创建一个。碰巧的是,编译器不会费心标记自动生成的类 [Serializable]
.不幸的是,但这就是生活:-)
说了这么多(很多话,不是吗?:-),并假设你发誓不通过任何非静态和非 [Serializable]
方法,这是您的新 RunInAppDomain
方法:
/// <summary>
/// Executes a method in a separate AppDomain. This should serve as a simple replacement
/// of running code in a separate process via a console app.
/// </summary>
public static T RunInAppDomain<T>(Func<T> func)
{
AppDomain domain = AppDomain.CreateDomain("Delegate Executor " + func.GetHashCode(), null,
new AppDomainSetup { ApplicationBase = Environment.CurrentDirectory });
try
{
domain.SetData("toInvoke", func);
domain.DoCallBack(() =>
{
var f = AppDomain.CurrentDomain.GetData("toInvoke") as Func<T>;
AppDomain.CurrentDomain.SetData("result", f());
});
return (T)domain.GetData("result");
}
finally
{
AppDomain.Unload(domain);
}
}
[Serializable]
private class ActionDelegateWrapper
{
public Action Func;
public int Invoke()
{
Func();
return 0;
}
}
public static void RunInAppDomain(Action func)
{
RunInAppDomain<int>( new ActionDelegateWrapper { Func = func }.Invoke );
}
关于c# - 用 AppDomains 替换 Process.Start,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1510466/
关闭。这个问题是opinion-based .它目前不接受答案。 想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题. 5年前关闭。 Improve t
我是一名设计老师,试图帮助学生应对编程挑战,所以我编码是为了好玩,但我不是专家。 她需要找到 mode (最常见的值)在使用耦合到 Arduino 的传感器的数据构建的数据集中,然后根据结果激活一些功
我正在开发一个应用程序,该应用程序提供 CPU 使用率最高的 5 个应用程序名称。目前,我通过以下代码获得了排名前 5 的应用程序: var _ = require('lodash');
互联网上很少有例子涉及这个问题的所有三个问题——即 set-process-sentinel ; set-process-filter ;和 start-process . 我尝试了几种不同的方法来微
如 this post 中所述,在 C# 中有两种调用另一个进程的方法。 Process.Start("hello"); 和 Process p = new Process(); p.StartInf
我试图让我的桨从白色变为渐变(线性),并使球具有径向渐变。感谢您的帮助!您可以在 void drawPaddle 中找到桨的代码。 这是我的目标: 这是我的代码: //球 int ballX = 50
考虑:流程(a)根据我的文字: A process is first entered at the time of simulation, at which time it is executed u
我真的希望 Processing 有用于处理数组的 push 和 pop 方法,但由于它没有,我不得不试图找出删除数组中特定位置的对象的最佳方法。我相信这对很多人来说都是基本的,但我可以使用一些帮助,
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 10 年前。 Improve thi
以编程方式,我如何确定 Windows 10 中的 3 个类别 应用 后台进程 Windows 服务 就像任务管理器一样? 即我需要一些 C# 代码,我可以确定应用程序列表与后台进程列表。检查 Win
当我导入 node:process它工作正常。但是,当我尝试要求相同时,它会出错。 这工作正常: import process from 'node:process'; 但是当我尝试要求相同时,它会引
我正在上一门使用处理的类(class)。 我在理解 map() 函数时遇到问题。 根据它的文档( http://www.processing.org/reference/map_.html ): Re
我试图执行: composer.phar update 并收到: Fatal error: Allowed memory size of 94371840 bytes exhausted (tried
给定一堆二维图像,如何使用 Processing/Processing.js 产生体积渲染效果? 目前我的想法是使用 java(类似于 imageJ)进行体积渲染 -> 获取体积渲染图像的面作为单独的
这是代码示例 var startInfo = new ProcessStartInfo { Arguments = commandStr, FileName = @"C:\Window
当我在 Processing(草图 > 导入库 > 添加库)中添加库时,它安装在哪里? 最佳答案 它们安装在您的 中速写本位置 . 您可以通过转到"file">“首选项”来查看和更改您的速写本位置。草
无聊的好奇... 我正在查看当前进程的一些属性: using(Process p = Process.GetCurrentProcess()) { // Inspect properties
我正在尝试在同一页面上运行多个草图。 初始化脚本指定: /* * This code searches for all the * in your page and loads each scrip
Process.Kill 后是否需要使用 Process.WaitForExit? 如果调用进程在调用 Process.Kill 后立即退出怎么办? 这会导致 Process.Kill 失败吗? 编辑
我尝试使用处理从麦克风获取频率。我混合了文档中的两个示例,但“最高”并不是真正的赫兹(a 是 440 赫兹)。 你知道如何拥有比这更好的东西吗? import ddf.minim.*; import
我是一名优秀的程序员,十分优秀!