例如,在下面的代码中,将创建一个'image'对象,然后在未来某个未知点收集垃圾
void MyFunction() {
Bitmap image = RetrieveImage();
DoSomething(image);
}
怎么样?
void MyFunction() {
DoSomething(RetrieveImage());
}
在这种情况下,一旦它移出范围,即在MyFunction结束后收集的对象垃圾。如果没有,有什么地方可以强制执行吗?
答案 0 :(得分:19)
没有。事实上,你并不真的希望它被垃圾收集 - 频繁地提示垃圾收集器会降低性能。
您要做的想要的是及时处理非托管资源 - 这就是IDisposable
所带来的地方,以及using
声明:
void MyFunction()
{
using (Bitmap image = RetrieveImage())
{
DoSomething(image);
}
}
当image.Dispose()
语句离开using
语句时,无论DoSomething
是否引发异常,都会调用DoSomething
。
你必须使用额外的变量 - 除非你改为Func<Bitmap>
取代void DoSomething(Bitmap image)
{
// Code here
}
...
DoSomething(RetrieveImage());
,所以代替:
void DoSomething(Func<Bitmap> imageProvider)
{
using (Bitmap image = imageProvider())
{
// Code here
}
}
...
DoSomething(() => RetrieveImage());
你有:
RetrieveImage
请注意,这并没有机会传递位图而没有它被处理 - 如果你想稍后再使用它可能会有问题。不过,至少知道它是一种很好的技术。
编辑:正如mbeckish在他的评论中指出的那样,仅仅在public void ApplyToEachLineInFile(string file, Action<string> action)
{
using (TextReader reader = File.OpenText(file))
{
string line;
while ((line = reader.ReadLine()) != null)
{
action(line);
}
}
}
内处理位图并没有太大的好处。以下是该模式的变体:
{{1}}
这里封装了“获取和处理”逻辑,而不会让调用者担心 - 但调用者在传递的逻辑复杂性方面仍然可以非常灵活。
答案 1 :(得分:4)
当对象超出范围时,不会发生垃圾收集。相反,它是框架中的自动内存管理功能。
http://msdn.microsoft.com/en-us/magazine/bb985010.aspx
你可以强迫.Net收集垃圾,但除非你遇到严重的内存问题,否则我不建议你走这条路。
答案 2 :(得分:3)
注意:您不想这样做。 .NET垃圾收集器比你(或我,或Jon Skeet或其他任何人)“更聪明”。
try
{
Bitmap image = RetrieveImage();
DoSomething(image);
}
finally
{
GC.Collect();
}
(假设没有任何超出范围的对象实现IDisposable)
答案 3 :(得分:0)
您可以使用以下命令强制执行垃圾收集:
正确处理后(请参阅Jons答案for using(){} - 语法)。
&LT;编辑&gt;
不要忘记(就像我刚才那样)
System.GC.WaitForPendingFinalizers();
之后。
&LT; /编辑&gt;
虽然不建议 - 正如乔恩所说。