2017-02-12 19 views
0

我最近开始分析我的WinForms应用程序,并注意到在滚动ListView时出现巨大的内存泄漏。C#巨大的内存泄漏当在ListView中使用OwnerDraw/DrawItem滚动时

如果我不通过.OwnerDraw和DrawItem执行我自己的自定义渲染,则不会发生此泄漏。

我的ListView由一个图像,文本和在选定对象上绘制的矩形组成。我错过了一些清理?它似乎是无休止地重绘东西,这就是内存使用量叠加的原因。

如果我连续向上和向下滚动列表,它会在10秒内爬到超过100mb的内存使用量。如果我不使用OwnerDraw,内存使用保持一致。

根据我看到的例子,虽然我的用法似乎有效。

感谢您的任何援助。

// ## Inside form load ## // 
listView2.OwnerDraw = true; 
listView2.DrawItem += new DrawListViewItemEventHandler(listView2_DrawItem); 

// ## How the items are added to the ListView (in form load) ## // 

// Create an image list 
ImageList imageList = new ImageList(); 
imageList.ImageSize = new Size(256, 178); 
imageList.ColorDepth = ColorDepth.Depth32Bit; 
// Assign the image list to the listView 
listView2.LargeImageList = imageList; 
// Create an array of 20 listView items 
ListViewItem[] items = new ListViewItem[20]; 

// Create 20 items 
for (int i = 0; i < 20; i++) 
{ 
    // Add the image for this item to the image list 
    imageList.Images.Add(Image.FromFile("myFile2.jpg")); 
    // Create the item 
    items[i] = new ListViewItem("Item"); 
    items[i].ImageIndex = i; 
    // Add the item to the listView 
    listView2.Items.Add(icons[i]); 
} 

// ## Draw item handler ## // 
private void listView2_DrawItem(object sender, DrawListViewItemEventArgs e) 
{ 
    Rectangle rect3 = new Rectangle(e.Bounds.Left + 10, e.Bounds.Top + 10, 256, 178); 
    Rectangle rect4 = new Rectangle(rect3.Left, e.Bounds.Top, rect3.Width, e.Bounds.Height + 14); 
    TextFormatFlags flags = TextFormatFlags.HorizontalCenter | 
      TextFormatFlags.Bottom | TextFormatFlags.WordBreak; 

    // Draw the image for this item 
    e.Graphics.DrawImage(e.Item.ImageList.Images[e.ItemIndex], rect3); 

    // Draw the text and the surrounding rectangle. 
    TextRenderer.DrawText(e.Graphics, e.Item.Text, new Font("Arial", 12), rect4, Color.Black, flags); 

    if (e.Item.Selected) 
    { 
     int width = e.Item.ImageList.Images[e.ItemIndex].Width; 
     int height = e.Item.ImageList.Images[e.ItemIndex].Height; 
     Brush brush = new SolidBrush(Color.FromArgb(180, 1, 1, 1)); 
     e.Graphics.FillRectangle(brush, rect3); 

     TextFormatFlags flags2 = TextFormatFlags.HorizontalCenter | 
      TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak; 

     // Draw the text 
     TextRenderer.DrawText(e.Graphics, e.Item.Text, new Font("Arial", 12), rect3, Color.White, flags2); 
    } 
} 
+0

是什么让你觉得你实际上是在泄漏内存(除了字体和画笔)? GC只在需要时设置;所以内存使用量往往会堆积起来,直到那时...... – TaW

+0

我现在要离开任务管理器。如果我不断地上下滚动,它可以在10秒内使用100MB的内存。我相信它是泄漏的,因为它在使用默认图纸时不会发生,只有在我控制图纸时才会发生。我还没有试图继续超过100+ MB,看看它是否被封锁。我担心由于标准格式绘图不会漏出(mem使用率没有随着默认绘制而上升) – PersuitOfPerfection

+0

听起来很正常。在GB RAM和没有竞争程序的机器上,100MB没有任何问题。添加缺少的使用条款,并尝试使其真正达到更大的“泄漏”。 – TaW

回答

0

的解决方案是使用:

this.listView2.LargeImageList.Draw(e.Graphics, gameItemRect.Left, gameItemRect.Top, gameItemRect.Width, gameItemRect.Height, e.ItemIndex); 

这使用而不是创建影像的副本内部手柄。 此外,刷子和字体需要在代码块之外进行预初始化,以防止为每次绘制事件和泄漏内存重新创建它们,正如@Tim所述。主要的内存泄漏是由于图像绘制调用。

现在内存使用情况与不使用OwnerDraw一致。

1

您需要处置新的Font(“Arial”,12)对象和Brush。

您泄漏的不只是内存,还泄漏了GDI对象。

您可以在表单加载时创建一次字体,并在关闭时对其进行处理(性能更好),或者使用DrawItem块中的使用块创建和处理它(需要更慢但更简单的代码)

+0

感谢您的信息!问题是,主要泄漏是在调用绘制图像列表项目。如果一切都被注释掉了,除了那个和rect3对象外,我可以通过在约10秒内上下滚动来泄漏100mb的内存 – PersuitOfPerfection