在c#中显示先前绘制的线条时,for循环后出现内存泄漏
本文关键字:循环 for 泄漏 内存 显示 绘制 | 更新日期: 2023-09-27 18:07:23
当我画线,然后迭代到for循环,它会导致高内存泄漏,然后几行后崩溃。
private Pen ReDrawFromGrid(Pen pen)
{
for (int parseDgV = 0; parseDgV < dataGridView1.Rows.Count; parseDgV++)
{
float redrawX1;
float redrawY1;
float redrawX2;
float redrawY2;
float.TryParse(dataGridView1.Rows[parseDgV].Cells[0].Value.ToString(), out redrawX1);
float.TryParse(dataGridView1.Rows[parseDgV].Cells[1].Value.ToString(), out redrawY1);
float.TryParse(dataGridView1.Rows[parseDgV].Cells[2].Value.ToString(), out redrawX2);
float.TryParse(dataGridView1.Rows[parseDgV].Cells[3].Value.ToString(), out redrawY2);
if (dataGridView1.Rows[parseDgV].Cells[5].Value.ToString() == "Solid")
{
dashRedraw = new float[1] { 10 };
}
else if (dataGridView1.Rows[parseDgV].Cells[5].Value.ToString() == "Dash")
{
dashRedraw = new float[2] { 10, 10 };
}
else if (dataGridView1.Rows[parseDgV].Cells[5].Value.ToString() == "Dot")
{
dashRedraw = new float[2] { 3, 5 };
}
else
{
dashRedraw = new float[1] { 10 };
}
pen = new Pen(dataGridView1.Rows[parseDgV].Cells[4].Style.BackColor);
pen.DashPattern = dashRedraw;
g.DrawLine(pen, redrawX1, redrawY1, redrawX2, redrawY2);
this.Refresh();
this.axDNVideoX1.Invalidate();
}
GC.Collect();
return pen;
}
我试图在这个for循环之前和之后放置dispose,但它导致没有绘制线。如何在不造成内存泄漏的情况下迭代绘制线条?
谢谢你的帮助!
这里是一个快速重写的基本绘图代码与一些小的调整:
static float[] patSolid = new float[] { 10 };
static float[] patDash = new float[] { 10, 10 };
static float[] patDot = new float[] { 3, 5 };
private void RedrawFromGrid(Graphics g)
{
float X1, Y1, X2, Y2;
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
var cells = dataGridView1.Rows[i].Cells;
if (!float.TryParse(cells[0].Value.ToString(), out X1) ||
!float.TryParse(cells[1].Value.ToString(), out Y1) ||
!float.TryParse(cells[2].Value.ToString(), out X2) ||
!float.TryParse(cells[2].Value.ToString(), out Y2)
)
continue;
var style = cells[5].Value.ToString();
float[] pattern = patSolid;
if (style == "Dash")
pattern = patDash;
else if (style == "Dot")
pattern = patDot;
using (var pen = new Pen(cells[4].Style.BackColor))
{
pen.DashPattern = pattern;
g.DrawLine(pen, X1, Y1, X2, Y2);
}
}
}
它仍然有点脏,因为我想保持基本功能接近你的地方。
一些改进:
唯一需要在循环内分配的是pen
对象,您也可以通过缓存笔并重用它们来摆脱它。但是因为我们每次都在做分配,当你用完pen
时,它需要被处理掉。using
语句为您做到了这一点。您应该对调用this的方法中的Graphics
对象执行相同的操作。
最后,这种方法应该尽可能少的副作用。调用它的方法应该考虑副作用-在处理完Graphics
对象后调用this.Refresh()
或this.axDNVideoX1.Invalidate()
。
一般来说,绘图操作应该尽可能快,并且副作用尽可能少。分配数组,调用Invalidate
或Refresh
等都是调用者要做的。不要让你的绘图方法做任何事情,除了绘制。
编辑:
顺便说一下,调用GC.Collect()
不会解决内存泄漏。实际上,在这个上下文中,它很可能根本不会做任何事情,因为在这个循环中发生的分配无论如何都不会终止。当您发现自己直接调用垃圾收集器时,这几乎总是一个错误。
首先,参数"pen"对我来说没有意义。你正在传递一个Pen给你的方法,然后在你的方法中,你正在创建一个Pen的新实例,然后你返回一个Pen。我会缓存所有需要的Pen实例并重用它们。一旦你不再需要某支笔,就把它扔掉。
我看到的唯一"内存泄漏"令人担忧的代码部分是"axDNVideoX1",这似乎是一个ActiveX控件,它必须与视频做一些事情。试着注释掉这部分代码,看看是否还有内存泄漏。
我不会说'DrawLine'会导致内存泄漏。
关注创建和销毁的"GDI对象"的数量。您可以在任务管理器中看到这个值。
您正在创建一个Pen
每循环迭代。你需要妥善处理这些物品。传递给函数的笔会丢失,在循环中创建的笔也会丢失,除了最后一个被返回的笔。
using
块是你的朋友。使用它们。