C#未处理一次性对象,但使用的内存没有增加

C#未处理一次性对象,但使用的内存没有增加,c#,memory,disposable,C#,Memory,Disposable,我创建了这个简单的C#程序,希望它抛出OfMemoryException。 问题是它在不使用我所有笔记本电脑内存的情况下工作得很好。为什么?我怎样才能让它泄露所有的记忆 static void Main(string[] args) { for (int i = 0; true; i++) { new MustDispose(); } } class MustDispose { public MustDispose() {

我创建了这个简单的C#程序,希望它抛出OfMemoryException。 问题是它在不使用我所有笔记本电脑内存的情况下工作得很好。为什么?我怎样才能让它泄露所有的记忆

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());
    }

}

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

如果您想耗尽内存,则需要保留正在分配的内存

下面是一个足够简单的示例,在运行内存不足时应该不会出现问题:

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

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

如果您想耗尽内存,则需要保留正在分配的内存

下面是一个足够简单的示例,在运行内存不足时应该不会出现问题:

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

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

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

有各种各样的可能吃掉所有的记忆,例如

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

如果是,终结器将检查是否已调用Dispose()。如果没有,终结器将执行此操作。

在方法
MustDispose()
中,有一个字符非常重要:

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

有各种各样的可能吃掉所有的记忆,例如

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

如果是,终结器将检查是否已调用Dispose()。如果没有,终结器将执行此操作。

您如何创建示例您可以解释您如何创建示例您可以解释您还可以提到,尽管建议调用
Dispose
,但是
StreamReader
终结器将在收集对象时自动调用它。因此,在这种情况下,不显式调用
Dispose
的缺点是清理时间稍晚。
r
不会太大。
r.ReadToEnd()
返回的字符串可能远远大于该读取器,其作用域实际上小于该方法的作用域;它的生存期是调用
WriteLine
的范围。变量的范围与对象的生存期不同。CLR可以检测对象何时不再被引用,因此它们通常比作用域允许的时间更快地符合GC条件。@BrianRasmussen:你说得对。问题是,这些额外的信息是否会帮助OP,还是会让他感到困惑。因此,有时答案的质量是通过省略不必要的细节来定义的。也许这些评论正是提到这些事情的正确地方。感谢您这么做。您还可以提到,尽管建议调用
Dispose
,但是
StreamReader
终结器将在收集对象时自动调用它。因此,在这种情况下,不显式调用
Dispose
的缺点是清理时间稍晚。
r
不会太大。
r.ReadToEnd()
返回的字符串可能远远大于该读取器,其作用域实际上小于该方法的作用域;它的生存期是调用
WriteLine
的范围。变量的范围与对象的生存期不同。CLR可以检测对象何时不再被引用,因此它们通常比作用域允许的时间更快地符合GC条件。@BrianRasmussen:你说得对。问题是,这些额外的信息是否会帮助OP,还是会让他感到困惑。因此,有时答案的质量是通过省略不必要的细节来定义的。也许这些评论正是提到这些事情的正确地方。谢谢你这么做。