具有内存压力的 SafeHandle
SafeHandle with memory pressure
SafeHandle
class 允许在 .NET 下通过引用计数和 P/Invoke 编组器的合作来安全访问本机资源,以避免过早处置可能导致应用程序崩溃。
在某些情况下,通知垃圾收集器某些本机资源正在使用大量内存是有利的,例如,当所讨论的 "handle" 是包装本机拥有的大缓冲区时图书馆。 GC.AddMemoryPressure
may be used for this purpose; however, GC.RemoveMemoryPressure
必须在 "handle".
的生命周期结束时调用
这两种方法似乎不兼容:SafeHandle
是一个 CriticalFinalizerObject
,其 ReleaseHandle
方法在受限执行区域 (CER) 中运行。由于 GC.RemoveMemoryPressure
没有 ReliabilityContractAttribute
,因此不能从 CER 调用它(我猜想在关键的终结时间,GC 中与内存压力有关的某些部分可能不可用)。
我想到了两种方法,都很不优雅:
SafeHandle 可以包装到另一个对象中,该对象具有添加和消除内存压力的非关键终结器(和 Dispose 方法)。这有两个缺点:首先,有人可以在不处理包装器的情况下处理 SafeHandle(它必须公开以传递给本地方法),因此高估了内存压力。其次,当 SafeHandle 仍然存在时,包装器可能变得未被引用,因此内存压力被低估(可能更严重)。
SafeHandle 有一个管理内存压力的非关键可终结类型的字段。在这种情况下,上面的大多数问题都消失了,但是,句柄不能在其 Dispose 或 ReleaseHandle 方法中处理内存压力对象,因为这会导致 CER 中的 GC.RemoveMemoryPressure 调用。可以提供另一种方法(例如 DisposeNoncriticial),但这会导致 "slicing" 将句柄强制转换为 IDisposable 或在 using 块中使用时出现问题。
是否有创建具有相关内存压力的 SafeHandle 的通用模式?
在正常情况下包裹句柄而不暴露它是一个很好的模式。你可以像 FileStream
那样做那部分。据了解,句柄归FileStream
所有,关闭是非法的。这不是强制执行的,但这是合同。
第二个问题是您想将 SafeHandle
的生命周期与其包装器联系起来。 ConditionalWeakTable
class 允许您这样做。设计看起来像这样:
class Wrapper {
SafeHandle handle;
CWT cwt = new CWT() { { handle, this } };
~Wrapper() { RemoveMemoryPressure(); }
}
CWT 使包装器保持活动状态,前提是句柄处于活动状态。 CWT 用于将任意状态关联到不可扩展的对象,并且没有任何 GC 效果。
我不确定所有这一切是否值得,但它是一个解决方案(主要)满足您的要求。
此外,我不确定内存压力在多大程度上具有实际用途。
SafeHandle
class 允许在 .NET 下通过引用计数和 P/Invoke 编组器的合作来安全访问本机资源,以避免过早处置可能导致应用程序崩溃。
在某些情况下,通知垃圾收集器某些本机资源正在使用大量内存是有利的,例如,当所讨论的 "handle" 是包装本机拥有的大缓冲区时图书馆。 GC.AddMemoryPressure
may be used for this purpose; however, GC.RemoveMemoryPressure
必须在 "handle".
这两种方法似乎不兼容:SafeHandle
是一个 CriticalFinalizerObject
,其 ReleaseHandle
方法在受限执行区域 (CER) 中运行。由于 GC.RemoveMemoryPressure
没有 ReliabilityContractAttribute
,因此不能从 CER 调用它(我猜想在关键的终结时间,GC 中与内存压力有关的某些部分可能不可用)。
我想到了两种方法,都很不优雅:
SafeHandle 可以包装到另一个对象中,该对象具有添加和消除内存压力的非关键终结器(和 Dispose 方法)。这有两个缺点:首先,有人可以在不处理包装器的情况下处理 SafeHandle(它必须公开以传递给本地方法),因此高估了内存压力。其次,当 SafeHandle 仍然存在时,包装器可能变得未被引用,因此内存压力被低估(可能更严重)。
SafeHandle 有一个管理内存压力的非关键可终结类型的字段。在这种情况下,上面的大多数问题都消失了,但是,句柄不能在其 Dispose 或 ReleaseHandle 方法中处理内存压力对象,因为这会导致 CER 中的 GC.RemoveMemoryPressure 调用。可以提供另一种方法(例如 DisposeNoncriticial),但这会导致 "slicing" 将句柄强制转换为 IDisposable 或在 using 块中使用时出现问题。
是否有创建具有相关内存压力的 SafeHandle 的通用模式?
在正常情况下包裹句柄而不暴露它是一个很好的模式。你可以像 FileStream
那样做那部分。据了解,句柄归FileStream
所有,关闭是非法的。这不是强制执行的,但这是合同。
第二个问题是您想将 SafeHandle
的生命周期与其包装器联系起来。 ConditionalWeakTable
class 允许您这样做。设计看起来像这样:
class Wrapper {
SafeHandle handle;
CWT cwt = new CWT() { { handle, this } };
~Wrapper() { RemoveMemoryPressure(); }
}
CWT 使包装器保持活动状态,前提是句柄处于活动状态。 CWT 用于将任意状态关联到不可扩展的对象,并且没有任何 GC 效果。
我不确定所有这一切是否值得,但它是一个解决方案(主要)满足您的要求。
此外,我不确定内存压力在多大程度上具有实际用途。