用于高速应用程序的C#内存管理
我正在构建一个应用程序,该应用程序处理来自文件或缓冲区的传入图像,并以数组或固定大小的双倍形式输出结果。应用程序需要相对快速。我遇到了循环时间的问题。我在处理一幅图像时开始记录循环时间,它从最小的65毫秒开始逐渐增加到500毫秒,这太慢了。果不其然,我检查了内存使用情况,它也在稳步增长 我在每个循环后运行GC,并尽可能多地转储未使用的变量。我不会在处理循环中创建新对象。图像处理是在自己的线程上完成的,因此所有资源都会被转储。似乎大多数循环时间的增加发生在我从文件中提取图像时。我会错过什么 这是粗略的代码,完整的东西相当大。主要功能用于高速应用程序的C#内存管理,c#,memory,C#,Memory,我正在构建一个应用程序,该应用程序处理来自文件或缓冲区的传入图像,并以数组或固定大小的双倍形式输出结果。应用程序需要相对快速。我遇到了循环时间的问题。我在处理一幅图像时开始记录循环时间,它从最小的65毫秒开始逐渐增加到500毫秒,这太慢了。果不其然,我检查了内存使用情况,它也在稳步增长 我在每个循环后运行GC,并尽可能多地转储未使用的变量。我不会在处理循环中创建新对象。图像处理是在自己的线程上完成的,因此所有资源都会被转储。似乎大多数循环时间的增加发生在我从文件中提取图像时。我会错过什么 这是粗
private void button4_Click(object sender, EventArgs e)
{
Stopwatch sw = new Stopwatch();
sw.Start();
cogDisplay1.Image = null;
ImageFromFile.Operator.Open(Properties.Settings.Default.ImageFile, CogImageFileModeConstants.Read);
ImageFromFile.Run();
cogDisplay1.Image = ImageFromFile.OutputImage;
cogDisplay1.AutoFit = true;
Thread t = new Thread(Vision);
t.Start();
textBox3.Clear();
sw.Stop();
textBox3.AppendText(sw.ElapsedMilliseconds.ToString() + Environment.NewLine + "TS: " + t.ThreadState.ToString());
textBox3.AppendText("GC" + GC.GetTotalMemory(true).ToString());
GC.Collect(GC.MaxGeneration , GCCollectionMode.Forced, false);
}
图像处理
public void Vision()
{
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
AlignmentParams.ApproximateNumberToFind = 1;
AlignmentParams.SearchRegionMode = 0;
AlignmentResult = AlignmentPat.Execute(cogDisplay1.Image as CogImage8Grey, null , AlignmentParams);
Fixture.InputImage = cogDisplay1.Image;
Fixture.RunParams.UnfixturedFromFixturedTransform = AlignmentResult[0].GetPose();
Fixture.Run();
AlignmentResult = null;
#region FindLineTools
#endregion
#region FindEllipse
#endregion
sw.Stop();
SetText("V" + sw.ElapsedMilliseconds.ToString() + Environment.NewLine);
}
catch (Exception err)
{
SetText(Environment.NewLine + "***********Error***********" + Environment.NewLine);
SetText(err.ToString() + Environment.NewLine);
SetText("***************************" + Environment.NewLine);
}
}
首先,我建议发布一个经过清理的代码,以提高可读性(删除所有已注释的内容)。第二,只关注关键部分,即:您的问题是由于繁重的图像处理而导致的内存过度使用/泄漏(如果错误则纠正)。因此,在名为
Vision
的线程中,取消对图像对象的引用,并在处理完成后立即将其设置为null(如上所述,GC对您的情况没有很大帮助)。以下代码片段简要演示了该概念:
public void Vision()
{
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
AlignmentParams.ApproximateNumberToFind = 1;
AlignmentParams.SearchRegionMode = 0;
AlignmentResult = AlignmentPat.Execute(cogDisplay1.Image as CogImage8Grey, null , AlignmentParams);
Fixture.InputImage = cogDisplay1.Image;
Fixture.RunParams.UnfixturedFromFixturedTransform = AlignmentResult[0].GetPose();
Fixture.Run();
AlignmentResult = null;
// your coding stuff
sw.Stop();
SetText("V" + sw.ElapsedMilliseconds.ToString() + Environment.NewLine);
}
catch (Exception err)
{
SetText(Environment.NewLine + "***********Error***********" + Environment.NewLine);
SetText(err.ToString() + Environment.NewLine);
SetText("***************************" + Environment.NewLine);
}
finally{Fixture.InputImage=null}
不要给GC打对方付费电话。让VM决定何时内存不足,并且必须进行收集。通常情况下,您无法确定GC.Collect的最佳时间,除非您运行其他心跳或空闲的监视线程 其次,确保从方法调用接收到的任何资源都被释放。如果不将变量设置为NULL,则应显式调用Dispose或在Using块中调用:
using(SomeResource resource = Class.GiveMeResource("image.png"))
{
int width = resource.Width;
int height = resource.Height;
Console.Write("that image has {0} pixels", width*height);
} //implicitly calls IDisposable.Dispose() here.
您还需要进行一些内存和调用分析,以检测哪里存在泄漏(如果有)。您缺少本文中的代码;)
GC.Collect
不是魔杖。它不会从仍然被引用的堆栈中收集资源。它不收集非托管内存。最后,如果您让处理器非常繁忙,GC可能无法在再次休眠之前清除那么多资源。代码对于决定哪些(如果其中任何一个)有助于您丢失内存探查器诊断非常重要,该诊断会告诉您应用程序泄漏的原因。GC.Collect完全不起任何作用。这相当于对着电脑喊“收集”。如果有任何影响的话,它只会损害性能。“在自己的线程上完成,以便转储所有资源”这根本不能保证。您需要一个AppDomain。你声称这让我想知道你的实际资源处理。