【问题标题】:C# Disposable Objects not disposed but memory used not increasingC# Disposable Objects 未处置但使用的内存未增加
【发布时间】:2014-09-26 15:57:29
【问题描述】:

我创建了这个简单的 C# 程序,期望它抛出 OutOfMemoryException。 问题是它可以在不使用我所有笔记本电脑内存的情况下完美运行。为什么?我怎样才能让它泄漏所有的内存?

static void Main(string[] args)
{
    for (int i = 0; true; i++)
    {
        new MustDispose();
    }
}


class MustDispose
{
    public MustDispose()
    {
        StreamReader r = null;
        r = File.OpenText("C:\\Users\\rverdelli\\Desktop\\asd.txt");
        if (r.EndOfStream) return;
        Console.WriteLine(r.ReadToEnd());
    }

}

【问题讨论】:

  • 您是如何创建示例的,请您解释一下

标签: c# memory disposable


【解决方案1】:

在您的方法MustDispose() 中,有一个字符很重要:

}

这定义了范围的结束,这意味着局部变量不再有效。不再有效会告诉垃圾收集器删除局部变量,特别是 r 以及所有尚未分配给变量的临时结果(即 r.EndOfStream 的布尔返回值和字符串 r.ReadToEnd() )。

吃掉所有记忆的可能性有很多种,例如

var keeper = new List<byte[]>();
while(true)
{
    keeper.Add(new byte[1024*1024]);
}

如果是IDisposable interface is implemented correctly,Finalizer 将检查 Dispose() 是否已经被调用。如果没有,Finalizer 会这样做。

【讨论】:

  • 您可能还提到,虽然调用Dispose推荐,但StreamReader 终结器会在收集对象时自动调用它。因此,在这种情况下,不显式调用 Dispose 的缺点是清理会稍晚一些。
  • r 不会那么大。 r.ReadToEnd() 返回的字符串有可能 大于那个读取器,它的作用域实际上小于那个方法的作用域;它的生命周期是WriteLine 的调用范围。
  • 变量的作用域和对象的生命周期不一样。 CLR 可以检测对象何时不再被引用,因此它们通常比范围允许的更快地符合 GC 条件。
  • @BrianRasmussen:你是对的。问题是,这些额外信息是否会帮助 OP 或让他感到困惑。因此,有时答案的质量是通过省略不必要的细节来定义的。也许 cmets 正是提到这些事情的正确地方。谢谢你这样做。
【解决方案2】:

循环的每次迭代都不会存储超出该迭代范围的任何状态,因此当它结束时,可以释放该迭代中分配的所有内存。

如果你想用完内存,你需要保留你正在分配的内存。

这是一个足够简单的示例,应该不会让您内存不足:

var data = Enumerable.Range(0, int.MaxValue)
    .Select(i => new int[int.MaxValue])
    .ToArray();
Console.WriteLine(data.Length);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-03
    • 1970-01-01
    • 2016-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多