C# 在终结器中调用GC.Collect是否合适?
我们有一个C# 在终结器中调用GC.Collect是否合适?,c#,garbage-collection,C#,Garbage Collection,我们有一个BitmapImage类,它包装了一个本机图像id和System.Drawing.Bitmap,并实现了IDisposable。图像id是作为我们使用的第三方imaging SDK的一部分创建的,该SDK使用整数标识指向某些像素数据的“图像”。图像id和位图都指向相同的底层像素数据 SDK在许多情况下很难正确使用,因此我们有一个facade层,它抽象了SDK,并为TIF和PDF文档提供了一个易于使用且无错误的API,其中一部分是为了确保尽快释放内存。具有数百页的300 DPI多页图像是
BitmapImage
类,它包装了一个本机图像id和System.Drawing.Bitmap
,并实现了IDisposable
。图像id是作为我们使用的第三方imaging SDK的一部分创建的,该SDK使用整数标识指向某些像素数据的“图像”。图像id和位图都指向相同的底层像素数据
SDK在许多情况下很难正确使用,因此我们有一个facade层,它抽象了SDK,并为TIF和PDF文档提供了一个易于使用且无错误的API,其中一部分是为了确保尽快释放内存。具有数百页的300 DPI多页图像是常见的位置,因此应用程序中的内存可能很高
我们当前正在调用Dispose
方法中的GC.Collect
,以立即释放内存。在对软件进行全面测试后,这是在释放底层像素数据后立即释放大量内存的唯一方法,尤其是在大型合并操作期间,我们可能会将数百页合并到一个文档中。它也是以这种方式实现的,这样开发人员就不会错误地尝试使用GC.Collect分散他们的代码,因为他们无论如何都不应该真正调用它
我的问题分为两部分:
- 当垃圾收集器调用终结器时,它是否也会立即释放内存,或者在这种情况发生之前会有很长一段时间?我们是否也应该在这里调用
?特别是在仅32位进程中,我们必须确保尽可能多地保留可用内存GC.Collect
- 我们使用的SDK是GdPicture,即使当您
处理他们的图形对象时,它也不会处理像素数据或图像引用。在开发人员释放它们之前,它会一直保留它们。我们需要保证,如果开发人员不手动调用
,资源就会被释放。是否适合在终结器中引用托管类,例如Dispose
?我在一些地方读到,除了从GraphicsObject.ReleaseImage(id)
之类的东西调用一些静态方法之外,不应该调用其他方法,但是除非我们调用它,否则内存将不会被释放SafeHandle
- 您只处理实现IDisposable的东西。在这种情况下,您需要做的就是实现Dispose。它所需要做的就是将“Dispose”命令传递给它包含的任何可处置的对象
- 实际上,您可以处理未老化的资源。在这种情况下,您应该首先实现终结器(因此,至少GC可以在应用程序关闭/收集时清理此终结器)。然后提供Dispose函数作为附加功能。但是我总是把终结器放在第一位,因为它会被保证调用
GC Collect只是“立即收集托管资源”。它们几乎适用于相反的情况(托管和未更改的资源)。我认为有点混乱。希望在共识中更加明确 您无法管理GCollection的时间。 GC-n发生在以下情况:系统的物理内存不足+托管堆上分配的对象使用的内存超过可接受的阈值。该阈值在进程运行时不断调整调用了GC.Collect方法。几乎在所有情况下,您都不必调用此方法,因为GC是连续运行的。Collect方法主要用于特殊情况和测试 GC优化引擎根据正在进行的分配确定执行收集的最佳时间。 终结器执行的确切时间未定义。要确保类实例的资源得到确定性释放,请实现Close()方法或提供IDisposable。Dispose实现+不保证两个对象的终结器以任何特定顺序运行+未指定终结器运行的线程。如果有人忘记处理,请使用析构函数 ~YourClass(){Dispose(false);} 转化为: 受保护的重写void Finalize(){try{…cleanup…}最终{base.Finalize();}
- 别忘了
public MyClass() { this.reader = new TextReader(); }
public class A : IDisposable
{
bool disposed = false; // Flag: Has Dispose already been called?
private Component handle;
private IntPtr umResource;
public void Dispose() {
Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) {
if (disposed) return;
if (disposing) { // Free managed resources
if (reader != null) reader.Dispose();
if (handle != null) handle.Close(); }
if (umResource != IntPtr.Zero) { // Free unmanaged resources
umResource = IntPtr.Zero; }
disposed = true; }
~A() { Dispose(false); } } // Only if we have real unmanaged resources
public class B : A {
private bool disposed = false;
protected override void Dispose(bool disposing) {
if (disposed) return;
if (disposing) { ... } // To free any managed objects
// Free unmanaged resources
disposed = true;
base.Dispose(disposing)} }