替换Process.Start与AppDomains(Replacing Process.Start with AppDomains)
背景
我有一个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事件添加到工作者域将使单元测试通过。 无论如何,我担心也许创建“工作者”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 ) ) { } }
Background
I have a Windows service that uses various third-party DLLs to perform work on PDF files. These operations can use quite a bit of system resources, and occasionally seem to suffer from memory leaks when errors occur. The DLLs are managed wrappers around other unmanaged DLLs.
Current Solution
I'm already mitigating this issue in one case by wrapping a call to one of the DLLs in a dedicated console app and calling that app via Process.Start(). If the operation fails and there are memory leaks or unreleased file handles, it doesn't really matter. The process will end and the OS will recover the handles.
I'd like to apply this same logic to the other places in my app that use these DLLs. However, I'm not terribly excited about adding more console projects to my solution, and writing even more boiler-plate code that calls Process.Start() and parses the output of the console apps.
New Solution
An elegant alternative to dedicated console apps and Process.Start() seems to be the use of AppDomains, like this: http://blogs.geekdojo.net/richard/archive/2003/12/10/428.aspx.
I've implemented similar code in my application, but the unit tests have not been promising. I create a FileStream to a test file in a separate AppDomain, but don't dispose it. I then attempt to create another FileStream in the main domain, and it fails due to the unreleased file lock.
Interestingly, adding an empty DomainUnload event to the worker domain makes the unit test pass. Regardless, I'm concerned that maybe creating "worker" AppDomains won't solve my problem.
Thoughts?
The Code
/// <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 () ); } }
The unit test
[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 ) ) { } }
原文:https://stackoverflow.com/questions/1510466
最满意答案
使用@Transient注释。 它告诉该成员不可持久。
Use the @Transient annotation. It tells that the member is not persistable.
相关问答
更多-
模特中的私人成员(Private members in Model)[2023-03-30]
使用@Transient注释。 它告诉该成员不可持久。 Use the @Transient annotation. It tells that the member is not persistable. -
Python中的私人成员(Private members in Python)[2023-10-22]
9.6。 私有变量 Python中不存在除对象内部无法访问的“私有”实例变量。 然而,大多数Python代码之后还有一个惯例:一个前缀为下划线的名称(例如_spam)应被视为API的非公开部分(无论是函数,方法还是数据成员) 。 应视为实施细节,恕不另行通知。 由于类私有成员有一个有效的用例(即避免名称与子类名称冲突的名称),对这种称为名称调整的机制的支持有限。 表单__spam的任何标识符(至少两个前导下划线,最多一个尾部下划线)以_classname__spam文本替换,其中classname是当前类名 ... -
甚至有可能没有“花哨”吗? 可悲的是,你必须要花哨 。 class Thing extends EventEmitter constructor: (name) -> @getName = -> name 记住, “只是JavaScript”。 Is it even possible without getting "fancy"? Sad to say, you'd have to be fancy. class Thing extends EventEmitter constructo ...
-
私有成员函数实际上不是继承的,您不能在子类中访问它们。 (除非您使用重载的私有虚拟成员函数 - 在这种情况下,您也无法访问基类成员函数,但它仍然是继承,但它有其他用例)。 但无论如何,你希望它们在基类中,因为它们被基类中的其他私有/受保护成员函数使用(直接或以链式方式)。 如果它没有被任何其他成员函数使用 - 那么你可以将其删除为未使用的代码。 同样在本文中, Herb Sutter建议并解释了私有虚拟成员函数的使用。 Private member functions actually are not in ...
-
您可能想要使用Yahoo模块模式 : myModule = function () { //"private" variables: var myPrivateVar = "I can be accessed only from within myModule." //"private" method: var myPrivateMethod = function () { console.log("I can be accessed only from ...
-
Java中的私人成员(Private members in Java)[2022-04-17]
尽管我为Java谋生11年,但当我在两年前发现这一事实时,我感到非常惊讶。 我以前一定读过它,但不知怎的,它从来没有沉入其中。我同意这个看起来很奇怪,但是当你考虑一下它时,它会变得非常有意义。 什么是OO? 关于问题和信息隐藏的分离,对吗? 因此,在你的设计中,你总是(应该)尽量避免在你自己关心的事情之外“知道”事情,因为这等于做出了假设; 在设计时你所“知道”的事情可能会在以后发生变化,并使你的班级正在制定的假设无效。 在这种情况下,你允许Foo访问另一个Foo的私人酒吧,这个酒吧最初感觉像'知道'Foo ... -
你的意思是使用一些指针算术来获得访问权限? 这是可能的,但绝对是危险的。 看看这个问题也访问私人成员 You mean using some pointer arithmetic to gain the access ? It is possible but is definitely dangerous. Take a look at this question also: Accessing private members
-
这是因为通过将其标记为私有,您告诉编译器只有Class1可以访问该变量。 即使您的构造函数是public ,变量本身仍然在Class1声明,因此它有权修改它。 即使它们可能是两个不同的实例 ,它们也是相同的变量声明。 但是,如果我是通过Class2做到这一点的话,那么它将不起作用: Class1 c1 = new Class1(); c1.field = "value"; // Won't compile 这实际上是从你的报价中解释的: 私人成员只能在班级内进入 That's because by mar ...
-
另一种解决方案可能是创建ImageField的子类并覆盖ImageField方法: class ImageWithThumbnailField(ImageField): def contribute_to_class(self, cls, name): super(ImageWithThumbnailField, self).contribute_to_class(cls, name) def photo_thumb(self): phot ...
-
访问班级中的私人成员(Accessing private members in a class)[2022-05-08]
如果您可以看到原始类,则可以使用相同的位模式创建一个mock类,并将原始对象强制转换为mock类对象 以下示例 原课 class ClassWithHiddenVariables { private: int a; double m; }; 模拟课 class ExposeAnotherClass { public: int a_exposed; double m_exposed; }; 如果要查看ClassWithHidde ...