【发布时间】:2014-05-15 12:10:38
【问题描述】:
我正在尝试编写一个类来包装使用Marshal.AllocHGlobal 分配的缓冲区。我实现了IDisposable 接口,并添加了一个终结器,当我不再需要它时(当对象超出范围时)应该释放内存。
当我测试类时,GC 不会调用我的类的终结器或 Dispose 方法,即使它们超出了范围。结果,我得到了OutOfMemoryException。
GC为什么不调用finalizer,为什么内存没有被释放?
这是一个说明问题的简短示例。在示例中,没有任何内容写入控制台(Unhandled Exception: OutOfMemoryException. 除外)
class Buffer : IDisposable
{
public IntPtr buf { get; set; }
public Buffer()
{
buf = Marshal.AllocHGlobal(4 * 1024 * 1024);
}
~Buffer()
{
Console.WriteLine("Finalizer called");
Dispose(false);
}
public void Dispose()
{
Console.WriteLine("Dispose called");
Dispose(true);
GC.SuppressFinalize(this);
}
internal virtual void Dispose(bool disposing)
{
if (buf != IntPtr.Zero)
{
Console.WriteLine("Releasing memory");
Marshal.FreeHGlobal(buf);
buf = IntPtr.Zero;
}
}
}
class Program
{
static void Main(string[] args)
{
while(true)
{
Buffer b = new Buffer();
Thread.Sleep(20);
}
}
}
编辑:这是我的测试程序崩溃时的 .NET 性能计数器:
【问题讨论】:
-
您分配内存的速度超过了垃圾收集器通过调用范围外对象的终结器来回收它的速度。
-
内存不足异常是物理内存不足吗?
-
@Matt 不,我有 8 GB 的 RAM,测试程序最大使用 1.8 GB(当它崩溃时)。即使它使用 1.8GB,我仍然有大约 4.3GB 的可用物理内存。
-
@martin_costello GC 甚至没有尝试回收任何东西。当它注意到可用内存变低时,它不应该启动吗?
-
.NET CLR 2 和 .NET CLR 4 具有不同的垃圾收集器。你用的是哪个版本?
标签: c# memory garbage-collection