未调用Dispose和Finalizer,发生OutOfMemoryException

Ove*_*Ove 0 c# memory garbage-collection

我正在尝试编写一个包含分配的缓冲区的类Marshal.AllocHGlobal.我实现了IDisposable接口,并添加了一个终结器,当我不再需要它时(当对象超出范围时)应释放内存.

当我测试类时,GC不会调用我的类的终结器或Dispose方法,即使它们超出了范围.结果,我得到了一个OutOfMemoryException.

为什么GC不会调用终结器,为什么内存不会被释放?

这是一个简短的例子来说明问题.在示例中,没有任何内容写入控制台(除外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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:这是我的测试程序崩溃时的.NET性能计数器: 表现计数器

Mar*_*age 5

您需要告诉垃圾收集器,使用单个IntPtr字段的非常小的托管对象在非托管内存方面成本很高.目前,垃圾收集器幸福地没有意识到每个小型托管对象都使用大量非托管内存并且没有理由执行任何收集.

分配非托管内存时可以使用GC.AddMemoryPressure,释放非托管内存时可以使用GC.RemoveMemoryPressure.