我是一个新的程序员,我只是想出了一个内存泄漏的问题。如果我在循环中声明一个变量以使其一次又一次地声明,我是否会泄漏内存?例如,我有
while(true)
{
Image<Gray, Byte> MyImage = new Image<Gray, Byte> (1024, 768);
//do something else
}
我知道这是一个无限循环,但我的问题是关于内存的。在这个循环中,内存使用量增长得很快吗?我应该手动释放 MyImage 吗?
我是一个新的程序员,我只是想出了一个内存泄漏的问题。如果我在循环中声明一个变量以使其一次又一次地声明,我是否会泄漏内存?例如,我有
while(true)
{
Image<Gray, Byte> MyImage = new Image<Gray, Byte> (1024, 768);
//do something else
}
我知道这是一个无限循环,但我的问题是关于内存的。在这个循环中,内存使用量增长得很快吗?我应该手动释放 MyImage 吗?
使用后需要打电话MyImage.Dispose()
。
另一种方法是将代码更改为:
while(true)
{
using(Image<Gray, Byte> MyImage = new Image<Gray, Byte> (1024, 768)){
//do something else
}
}
垃圾收集器 (GC) 最终会为您完成这项工作。在您建议的情况下,您必须小心,因为在这种情况下,GC 将尝试管理它花费在垃圾收集上的时间与应用程序内存消耗(工作集)。因此,应用程序可能会消耗比它需要的更多的内存,尤其是在您说明的情况下。
CLR 完全自动处理此内存,您永远不会自己释放托管内存。例如考虑以下
public void Test()
{
byte[] myArray = new Byte[1000];
// ...
}
执行时Test
,在内存堆上分配一个容纳 1000 字节的数组。该数组由变量引用myArray
,存储在局部变量堆栈中。当这个方法退出时,这个局部变量会弹出范围,这意味着没有任何东西可以引用内存堆上的数组。然后,孤立的数组就有资格被 GC 回收。但是,此收集可能不会立即发生,因为 CLR 决定是否收集是基于许多因素(可用内存、当前内存分配、自上次收集以来的时间等)。这意味着在垃圾收集前所用的时间。
鉴于上述情况,在您描述的情况下,您将在循环/包含方法的持续时间内大量增加内存消耗。在这里使用using
语句要好得多
while (true)
{
using (Image<Gray, Byte> MyImage = new Image<Gray, Byte> (1024, 768))
{
// ...
}
}
或在每个循环后调用dispose()
对象Image
。
while (true)
{
Image<Gray, Byte> MyImage = new Image<Gray, Byte> (1024, 768);
// ...
MyImage.Dispose();
}
另外:您始终可以通过查询性能计数器(使用 System.Diagnostics)自己检查此类内存消耗(测试进程的实际内存消耗):
string procName = Process.GetCurrentProcess().ProcessName;
using (PerformanceCounter pc = new PerformanceCounter("Process", "Private Bytes", procName))
Console.WriteLine(pc.NextValue());
注意:读取性能计数器需要管理员权限。
如果我在循环中声明一个变量以使其一次又一次地声明,我是否会泄漏内存?
不,您没有,其他人提到的问题可能是 Image 是否包装了 Image 对象
但是对于您的问题,在循环内声明一个变量并在每次迭代时为其分配一个新值并不是问题
在某些情况下,紧密的循环会导致 OOM 问题。但是,Image
实现IDisposable
,因此请务必通过using
语句调用它,以便在您完成资源时可以释放资源。
using (Image<Gray, Byte> MyImage = new Image<Gray, Byte>(1024, 768))
{
//do stuff
}
如果实现任何托管对象,请确保Image<T,U>
实现。IDisposable
Image<T,U>
在您问题的一般形式中,您本身并没有泄漏内存,但您增加内存占用的速度可能比 GC 减少它的速度更快(取决于您正在使用的对象的确切行为和内存占用)。如果是这样,这将产生很多类似内存泄漏的影响。
在您的具体示例中,Image 对象包含非托管资源,其中可能包括内存(或文件句柄或 GDI 对象等)。正如其他答案所指出的,如果您不处置,这些非托管资源将不会被回收(或者如果它们具有终结器,则可能会在 GC 的第二次通过时被回收)。