【问题标题】:SafeHandle with memory pressure具有内存压力的 SafeHandle
【发布时间】:2016-08-03 21:24:04
【问题描述】:

SafeHandle 类允许通过引用计数和 P/Invoke 编组器的合作安全访问 .NET 下的本机资源,以避免过早处理可能导致应用程序崩溃的句柄。

在某些情况下,通知垃圾收集器某些本机资源正在使用大量内存是有利的,例如,当所讨论的“句柄”是一个封装的本机库拥有的大缓冲区时。 GC.AddMemoryPressure 可用于此目的;但是,GC.RemoveMemoryPressure 必须在“句柄”的生命周期结束时调用。

这两种方法似乎不兼容:SafeHandleCriticalFinalizerObject,它的 ReleaseHandle 方法在受限执行区域 (CER) 中运行。由于GC.RemoveMemoryPressure 没有ReliabilityContractAttribute,因此不能从CER 调用它(我猜在关键的完成时间,GC 的某些与内存压力有关的部分可能不可用)。

我想到了两种方法,都很不雅:

  1. 可以将 SafeHandle 包装到另一个对象中,该对象具有添加和消除内存压力的非关键终结器(和 Dispose 方法)。这有两个缺陷:首先,有人可以在不处理包装器的情况下处理 SafeHandle(它必须暴露才能传递给本地方法),因此内存压力被高估了。其次,当 SafeHandle 还活着时,包装器可能会变得未被引用,因此内存压力被低估了(可能更严重)。

  2. SafeHandle 有一个管理内存压力的非关键可终结类型的字段。在这种情况下,上面的大多数问题都消失了,但是,句柄无法在其 Dispose 或 ReleaseHandle 方法中释放内存压力对象,因为这会导致 CER 中的 GC.RemoveMemoryPressure 调用。可以提供另一种方法(例如 DisposeNoncriticial),但是当句柄被强制转换为 IDisposable 或在 using 块中使用时,这会导致“切片”问题。

是否有创建具有相关内存压力的 SafeHandle 的通用模式?

【问题讨论】:

    标签: c# .net garbage-collection safehandle constrained-execution-reg


    【解决方案1】:

    在正常情况下包裹句柄而不暴露它是一个很好的模式。你可以像FileStream 那样做那部分。据了解,该句柄归FileStream所有,关闭是违法的。这不是强制执行的,但这是合同。

    第二个问题是您希望将SafeHandle 的生命周期与它的包装器联系起来。 ConditionalWeakTable 类允许您这样做。设计如下所示:

    class Wrapper {
     SafeHandle handle;
     CWT cwt = new CWT() { { handle, this } };
    
     ~Wrapper() { RemoveMemoryPressure(); }
    }
    

    如果句柄处于活动状态,则 CWT 使包装器保持活动状态。 CWT 用于将任意状态关联到不可扩展的对象,并且不会产生任何 GC 效果。

    我不确定所有这些是否值得,但它会是(大部分)满足您的要求的解决方案。

    另外,我不确定内存压力在多大程度上有实际用途。

    【讨论】:

    • 很好,我没有想到这个!我的用例是存储非常大(> 几 GB)的数组,并将它们传递给本地线性代数库,该库也负责分配和释放它们。我想将这些恶作剧告诉 CLR 不会有什么坏处……
    • 我不是这方面的专家,但我不知道它会如何处理这些信息。它不知道什么对象在什么时间点死亡。它也不知道什么对象与内存压力相关联。 comutilnative.cpp 中有一个简短的解释,但它不适用于您的情况。 GC 永远不应该清理任何这些对象,因为您必须确定性地处置它们。在实践中永远不应该调用终结器。
    • 有趣的是,CoreCLR 的comutilnative.cpp 基本上总是会触发 GC 是内存压力超过托管堆大小的 30%。在我的情况下,我想它几乎总是(当它很重要时),所以也许我可以避免在内存压力计费上失眠,而只是分析在大量分配之前调用 GC.Collect() 是否有任何优势。
    • 如果您维护本机内存并始终正确处理它,那么 GC 应该没什么可做的。触发它不会做任何事情。 如果你想触发你可能应该在丢弃很多对象后触发。
    猜你喜欢
    • 2014-02-14
    • 2011-12-08
    • 1970-01-01
    • 2018-11-26
    • 2014-09-01
    • 2021-11-03
    • 2014-09-30
    • 1970-01-01
    • 2013-12-08
    相关资源
    最近更新 更多