首页 > 解决方案 > 发现内存泄漏

问题描述

我对以下代码有疑问。我在 GetDB 函数中创建了一个内存流,并在using块中使用了返回值。出于某种未知原因,如果我转储我的对象,我发现 MemoryStream 仍然在 Main 方法的末尾。这导致我大量泄漏。知道如何清理这个缓冲区吗?

我实际上已经检查过在 MemoryStream 上调用了 Dispose 方法,但该对象似乎仍然存在,我已使用 Visual Studio 2017 的诊断工具来完成此任务。

class Program
{
    static void Main(string[] args)
    {
        List<CsvProduct> products;
        using (var s = GetDb())
        {
            products = Utf8Json.JsonSerializer.Deserialize<List<CsvProduct>>(s).ToList();
        }
    }

    public static Stream GetDb()
    {
        var filepath = Path.Combine("c:/users/tom/Downloads", "productdb.zip");
        using (var archive = ZipFile.OpenRead(filepath))
        {
            var data = archive.Entries.Single(e => e.FullName == "productdb.json");
            using (var s = data.Open())
            {
                var ms = new MemoryStream();
                s.CopyTo(ms);
                ms.Seek(0, SeekOrigin.Begin);
                return (Stream)ms;
            }
        }
    }
}

标签: c#

解决方案


出于某种未知原因,如果我转储我的对象,我发现 MemoryStream 仍然在 Main 方法的末尾。

这并不是特别不正常。GC 是单独发生的。

这导致我大量泄漏。

这不是泄漏,它只是内存使用。

知道如何清理这个缓冲区吗?

我可能只是不使用 aMemoryStream,而是返回包装实时解压缩流的内容(来自s = data.Open())。但是,这里的问题是您不能返回s-archive离开该方法时仍然会被处理掉。因此,如果我需要解决这个问题,我会创建一个自定义Stream来包装内部流并在处理时处理第二个对象,即

class MyStream : Stream {
    private readonly Stream _source;
    private readonly IDisposable _parent;
    public MyStream(Stream, IDisposable) {...assign...}

    // not shown: Implement all Stream methods via `_source` proxy

    public override void Dispose()
    {
        _source.Dispose();
        _parent.Dispose();
    }
}

然后有:

public static Stream GetDb()
{
    var filepath = Path.Combine("c:/users/tom/Downloads", "productdb.zip");
    var archive = ZipFile.OpenRead(filepath);
    var data = archive.Entries.Single(e => e.FullName == "productdb.json");
    var s = data.Open();
    return new MyStream(s, archive);
}

(可以稍微改进以确保archive在我们成功返回之前发生异常时处理)


推荐阅读