我制作了一个处理图像的软件。它试图在图像中找到模式,如果它找到了它所寻找的模式,它会将图像名称,模式类型和坐标写入文本文件中。
您可能知道,图像处理需要很长时间。所以我决定使用多线程来提高性能。
bool Multithread = CheckMultithread();
UpdateParameters();
if (Multithread)
{
Parallel.For(0, FileNames.Length ,i => Solve(FileNames[i]));
}
else
{
foreach (string s in FileNames)
{
Solve(s);
}
}
这是我第一次尝试在C#中使用多线程。但我这里没有多线程相关的错误,因为处理不会干扰另一个图像的处理。
问题是:如果多线程处于ON状态,当我到达第200个左右的图像时,我得到一个OutOfMemoryException ...显然,这种并行性(实际上整个代码在不同的线程中运行)消耗N倍的内存( N ==正在运行的线程数)...
我修改了我创建的每个类,只有一个使用非托管代码(QuickBitmap.cs,Bitmap类的包装器,使用lockbits和unlockbits来提高性能)。 但是我在那个类中实现了IDisposable接口,所以......我不知道为什么会这样。
每个线程需要+/- 400 mb的ram才能运行。 当抛出OutOfMemoryException时,程序使用大约1300 mb的ram。即使我有超过9 GB的可用内存
为了处理这个异常,我在Solve()
的求助中添加了以下代码 if (GC.GetTotalMemory(false) > 1000*1000*1000)
{
lock (Manager.dasLock)
{
Manager.sw.Start();
GC.Collect();
Manager.sw.Stop();
}
}
ProcessedCount是一个 static int 在lock()语句中递增。
添加该段代码后,程序可以处理所有图像(2000+)而不会抛出任何异常。我也从不使用超过1.5 GB的ram。
但是因为每个人都因为DARING而打电话给全能的GC ...... 我能做些什么来防止这种情况?
如果你们想要,我可以发布更详细的代码。
Ps:在Solve()的最后几行中,我使用非托管资源调用每个对象的Dispose,并将所有变量设置为null。
Pps:是的,这是一个32位软件,但限制应该是4 GB而不是1.5,对吗?
Edit3:更改GC.Collect调用代码。这样我就可以知道我花了多少时间收集。对于每一分钟的处理,我都会花0.4秒收集。
答案 0 :(得分:1)
限制线程数解决了问题:
if (Multithread)
{
ParallelOptions pOptions = new ParallelOptions();
pOptions.MaxDegreeOfParallelism = Environment.ProcessorCount;
Parallel.For(0, FileNames.Length, pOptions, i => Solve(FileNames[i]));
}
else
{
foreach (string s in FileNames)
{
Solve(s);
}
}
答案 1 :(得分:0)
虽然没有说明,但如果您正在进行图像处理,那么您正在处理的某些对象很可能会实现IDisposable接口 - 例如File或Image对象。
对于所有这些对象,您应该尝试使用"使用"块(See here)。
更有可能的是,当你调用GC.Collect它正在处理这些对象,这就是我在你调用GC时所理解的原因。收集你没有得到例外