首页 \ 问答 \ 替换Process.Start与AppDomains(Replacing Process.Start with AppDomains)

替换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
更新时间:2023-12-03 15:12

最满意答案

使用@Transient注释。 它告诉该成员不可持久。


Use the @Transient annotation. It tells that the member is not persistable.

相关问答

更多
  • 使用@Transient注释。 它告诉该成员不可持久。 Use the @Transient annotation. It tells that the member is not persistable.
  • 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谋生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 ...
  • 如果您可以看到原始类,则可以使用相同的位模式创建一个mock类,并将原始对象强制转换为mock类对象 以下示例 原课 class ClassWithHiddenVariables { private: int a; double m; }; 模拟课 class ExposeAnotherClass { public: int a_exposed; double m_exposed; }; 如果要查看ClassWithHidde ...

相关文章

更多

最新问答

更多
  • 您如何使用git diff文件,并将其应用于同一存储库的副本的本地分支?(How do you take a git diff file, and apply it to a local branch that is a copy of the same repository?)
  • 将长浮点值剪切为2个小数点并复制到字符数组(Cut Long Float Value to 2 decimal points and copy to Character Array)
  • OctoberCMS侧边栏不呈现(OctoberCMS Sidebar not rendering)
  • 页面加载后对象是否有资格进行垃圾回收?(Are objects eligible for garbage collection after the page loads?)
  • codeigniter中的语言不能按预期工作(language in codeigniter doesn' t work as expected)
  • 在计算机拍照在哪里进入
  • 使用cin.get()从c ++中的输入流中丢弃不需要的字符(Using cin.get() to discard unwanted characters from the input stream in c++)
  • No for循环将在for循环中运行。(No for loop will run inside for loop. Testing for primes)
  • 单页应用程序:页面重新加载(Single Page Application: page reload)
  • 在循环中选择具有相似模式的列名称(Selecting Column Name With Similar Pattern in a Loop)
  • System.StackOverflow错误(System.StackOverflow error)
  • KnockoutJS未在嵌套模板上应用beforeRemove和afterAdd(KnockoutJS not applying beforeRemove and afterAdd on nested templates)
  • 散列包括方法和/或嵌套属性(Hash include methods and/or nested attributes)
  • android - 如何避免使用Samsung RFS文件系统延迟/冻结?(android - how to avoid lag/freezes with Samsung RFS filesystem?)
  • TensorFlow:基于索引列表创建新张量(TensorFlow: Create a new tensor based on list of indices)
  • 企业安全培训的各项内容
  • 错误:RPC失败;(error: RPC failed; curl transfer closed with outstanding read data remaining)
  • C#类名中允许哪些字符?(What characters are allowed in C# class name?)
  • NumPy:将int64值存储在np.array中并使用dtype float64并将其转换回整数是否安全?(NumPy: Is it safe to store an int64 value in an np.array with dtype float64 and later convert it back to integer?)
  • 注销后如何隐藏导航portlet?(How to hide navigation portlet after logout?)
  • 将多个行和可变行移动到列(moving multiple and variable rows to columns)
  • 提交表单时忽略基础href,而不使用Javascript(ignore base href when submitting form, without using Javascript)
  • 对setOnInfoWindowClickListener的意图(Intent on setOnInfoWindowClickListener)
  • Angular $资源不会改变方法(Angular $resource doesn't change method)
  • 在Angular 5中不是一个函数(is not a function in Angular 5)
  • 如何配置Composite C1以将.m和桌面作为同一站点提供服务(How to configure Composite C1 to serve .m and desktop as the same site)
  • 不适用:悬停在悬停时:在元素之前[复制](Don't apply :hover when hovering on :before element [duplicate])
  • 常见的python rpc和cli接口(Common python rpc and cli interface)
  • Mysql DB单个字段匹配多个其他字段(Mysql DB single field matching to multiple other fields)
  • 产品页面上的Magento Up出售对齐问题(Magento Up sell alignment issue on the products page)