【问题标题】:Out of memory exception in .net winform treeview.net winform 树视图中的内存不足异常
【发布时间】:2013-04-22 12:55:35
【问题描述】:

我有一个树视图,并且基于树视图的项目,我在右侧有列表视图。所以几乎 UI 就是我们的 windows Explorer 那种外观。所以现在我面临的问题是,当我从右侧的列表视图中删除大量对象时,左侧的树视图变成了部分绘制(我可以说是一小部分)。当我从 VS IDE 附加 CLR 异常时,它指向行 sampletree.EndUpdate();除了内存不足。当我在列表视图中添加下一个项目时,一切正常,我的意思是树视图已完全绘制 我得到的例外是

System.OutOfMemoryException occurred
  Message=Out of memory.
  Source=System.Drawing
  StackTrace:
       at System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)
       at System.Drawing.Font.ToLogFont(Object logFont)
       at System.Drawing.Font.ToHfont()
       at System.Windows.Forms.Control.FontHandleWrapper..ctor(Font font)
       at System.Windows.Forms.OwnerDrawPropertyBag.get_FontHandle()
       at System.Windows.Forms.TreeView.CustomDraw(Message& m)
       at System.Windows.Forms.TreeView.WmNotify(Message& m)
       at System.Windows.Forms.TreeView.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd, Message& m)
       at System.Windows.Forms.Control.WmNotify(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.UserControl.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
       at System.Windows.Forms.Control.DefWndProc(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.TreeView.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, Int32 wParam, Int32 lParam)
       at System.Windows.Forms.Control.EndUpdateInternal(Boolean invalidate)
       at System.Windows.Forms.TreeView.EndUpdate()

你知道为什么我的树视图只画了一小部分而连续的修改完全画了吗?代码sn-p如下图e

 if( ( values != null ) &&
       ( values .OverallState != ToBeDeleted ) &&
       ( values .OverallState != .Deleted ) )
    {
       TreeView tree = this.TreeView;
       if( tree != null )
       {
          tree.BeginUpdate();
       }
       TryUpdate();
       TryPopulate();
       if( tree != null )
       {
          tree.EndUpdate();  // here exception coming
       }
    }

更新 我是这样使用字体的

case State.Modified:
                     NodeFont = new Font(TreeView.Font, FontStyle.Bold);
break;

这有什么问题吗

【问题讨论】:

  • winform 树视图是否有任何已知问题,或者任何索引都变为-1?
  • 这里有同样的问题。任务管理器显示该进程创建了 10,000 个 GDI 字体句柄(然后崩溃,最大为 10,000 个)。只有当我同时创建很多节点时才会发生这种情况。

标签: c# visual-studio-2010 listview treeview out-of-memory


【解决方案1】:

这种崩溃通常是由 GDI 资源泄漏引起的。这通常是由于忘记在任何 System.Drawing 类对象上调用 Dispose() 方法引起的。通常垃圾收集器会在您之后进行清理,但是,尤其是当您使用 ownerdraw 时,它可能不会经常运行,无法让您远离麻烦。当您消耗了 10,000 个 GDI 对象时,Windows 会拔掉您的程序的插头,结果就是 kaboom。

您可以从任务管理器轻松诊断此问题。查看 + 选择列并勾选句柄、用户对象和 GDI 对象。在您使用过程时,请注意为您的过程添加的那些列。稳步攀升的数字预示着 OOM Kaboom。

首先查看您的 DrawNode 事件处理程序,因为它可能会被频繁调用。但它也可能是由其他绘画代码引起的。确保使用 using 语句创建图形、钢笔、画笔、字体等绘图对象,以保证它们在使用后被处理掉。您从任务管理器获得的诊断信息会告诉您何时领先。

【讨论】:

  • 你可能是对的,我现在想知道的是什么时候出现问题(树视图切割一半)删除很多对象后,再次添加单个对象时,一切都会恢复正常,这是什么原因??
  • 没有必要对此感到疑惑,显然更少的数据会导致您可能忘记处理的更少句柄。用事实说话,任务管理器告诉你什么?
  • 任务管理器显示句柄、用户对象和 GDI 对象的计数增加,但不是连续的,它在某处停止并开始减少到某个值。我修改了我的问题。使用字体时,我没有使用 using 语句
  • 看起来问题(缺少 Dispose(),使用 {} 块)出在 .NET 内部绘图方法本身。问题出现在更改 NodeFont,而不是自定义节点绘图代码(GDI 对象上升 10,000)。问题也不是因为创建了几个 Font() 实例(您可以只创建一个),而是问题是我们更改了几个节点的 NodeFont。 (TreeView .NET 绘图代码在内部创建 LOGFONT 或 HFONT,并没有立即处理对象。)
  • 我认为这也是树视图中的错误。我启动了 processexplorer,每次设置节点文本时,它都会显示 GDI 计数增加 4k。当然,这不会持续很长时间。这是在最初完全加载树之后。最初一切都很好。尝试编辑一个节点文本,砰的一声,GDI 数量猛增。这似乎与树的大小有关。我要试试syncfusion的树。
【解决方案2】:

我刚刚遇到了完全相同的问题。它似乎只发生在 XP 之后的 Windows 系统中,并且当我删除 BeginUpdate()EndUpdate() 调用时,它不会发生。

因此,作为一种解决方法,我会说尝试删除 BeginUpdate()EndUpdate() 调用。这确实意味着在更新节点时可能会出现一些视觉卡顿,但从好的方面来说,它不会崩溃。这肯定是一场净胜。

我在 MSDN/Connect 上找不到任何解决此问题的内容,而且我现在没有时间整理一个独立的测试用例,但我确实认为这是处理 TreeViews 中的批量更新的错误在更高版本的 Windows 中。

【讨论】:

  • 另外,如果您只是将BeginUpdate() 替换为myTreeView.Visible = false 并将EndUpdate() 替换为myTreeView.Visible = true - 您可以避免所有屏幕闪烁并且仍然不会遇到错误。 (这似乎也有相当不错的表现。)
【解决方案3】:

您可以在更改节点字体或颜色后使用System.GC.Collect() 强制垃圾收集器。

【讨论】:

    猜你喜欢
    • 2016-09-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-23
    相关资源
    最近更新 更多