WinForms错误:缓冲操作当前正在进行中,无法释放BufferedGraphicsContext 的可能原因和解决方法

http://www.genshuixue.com/i-cxy/p/8047746
WinForms错误:缓冲操作当前正在进行中,无法释放BufferedGraphicsContext 的可能原因和解决方法
来源:博客园 2010-01-22

上一篇文章(对WebMatrix 进行现代化改造, 使其完美支持中文)里, 我谈了如何修改WebMatrix使其支持中文. 文章末尾提到已经能正常显示选择中文了, 但时不时会弹出一个错误: 缓冲操作当前正在进行中,无法释放BufferedGraphicsContext , 如图:

image_thumb[1]

 

我不懂这个错误是怎么发生的, 所以我在最外层的错误处理函数出加了一个断点, 结果发现每次异常发生的时候, 错误信息都不一样(汗~~~~), 有时是"参数无效", 此时调用堆栈是:

在 System.Drawing.Graphics.GetHdc() 
在 Microsoft.Matrix.UIComponents.SourceEditing.TextView.MeasureString(Char[] chars, Int32 startIndex, Int32 length) 位置 D:\projects\Visual Studio Projects\VS2008\AppMatrix\Matrix.Core\UIComponents.SourceEditing\TextView.cs:行号 2116 
在 Microsoft.Matrix.UIComponents.SourceEditing.TextView.GetActualIndex(TextLine line, Int32 xPos) 位置 D:\projects\Visual Studio Projects\VS2008\AppMatrix\Matrix.Core\UIComponents.SourceEditing\TextView.cs:行号 349 
在 Microsoft.Matrix.UIComponents.SourceEditing.TextView.GetLineColFromXY(Int32 x, Int32 y) 位置 D:\projects\Visual Studio Projects\VS2008\AppMatrix\Matrix.Core\UIComponents.SourceEditing\TextView.cs:行号 369 
在 Microsoft.Matrix.UIComponents.SourceEditing.TextView.OnMouseMove(MouseEventArgs e) 位置 D:\projects\Visual Studio Projects\VS2008\AppMatrix\Matrix.Core\UIComponents.SourceEditing\TextView.cs:行号 1749 
在 System.Windows.Forms.Control.WmMouseMove(Message& m) 
在 System.Windows.Forms.Control.WndProc(Message& m) 
在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 
在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 
在 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

有时是"System.OutOfMemoryException: 无法创建与屏幕兼容的位图。无法确定屏幕位图格式", 调用堆栈是:

在 System.Drawing.BufferedGraphicsContext.bFillBitmapInfo(IntPtr hdc, IntPtr hpal, BITMAPINFO_FLAT& pbmi) 
在 System.Drawing.BufferedGraphicsContext.CreateCompatibleDIB(IntPtr hdc, IntPtr hpal, Int32 ulWidth, Int32 ulHeight, IntPtr& ppvBits) 
在 System.Drawing.BufferedGraphicsContext.CreateBuffer(IntPtr src, Int32 offsetX, Int32 offsetY, Int32 width, Int32 height) 
在 System.Drawing.BufferedGraphicsContext.AllocBuffer(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle) 
在 System.Drawing.BufferedGraphicsContext.AllocBufferInTempManager(Graphics targetGraphics, IntPtr targetDC, Rectangle targetRectangle) 
在 System.Drawing.BufferedGraphicsContext.Allocate(IntPtr targetDC, Rectangle targetRectangle) 
在 System.Windows.Forms.Control.WmPaint(Message& m) 
在 System.Windows.Forms.Control.WndProc(Message& m) 
在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 
在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 
在 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

我在网上搜了下, 有好些朋友也都碰到相同问题, 但没搜到一个解决方法. 后来到google点com搜英文资料, 搜到了一篇英文文章, 文中没有给出直接的解决方法, 但给我了一个提示, 后来根据这个提示对代码做了相应的修改后, 这个错误再没出现.

此文连接:http://nomagichere.blogspot.com/2008/03/systemcomponentmodelwin32exception-is.html  (托伟大的GFW的福, 我们人人都成了爬墙专家)

文中重点内容如下:

We've been trying to track down a really sneaky problem for months. Every now and then, at seemingly random times, our application crashes.

......

One day, while trolling the bug bucket looking for something to do, I found an issue about disposing Graphics objects. That's a good thing to do, I figured, so I dug into the code and looked for CreateGraphics() calls. To my dismay, there were quite a few that were not being disposed, or were not in a using() block.

I added the calls to Dispose(), or put the objects in a using() block, and went on my way.

A couple of weeks later, one of our developers stopped by my desk to ask about a strange thing. He had been working on some automated testing of the application, and he noticed that all of a sudden, it stopped crashing. He had been getting lots of System.ComponentModel.Win32Exceptions after running his automated tests, and in the past few builds, they were gone.

......

大意是:

这几个月我们一直在查找一个非常诡异的bug....我们的应用程序时不时的崩溃, 看起来像是随性的

......

有一天, 我在bug跟踪软件浏览以便找件事情做的时候, 我发现了一个和销毁(Dispose)Graphics对象有关的问题, 我就跟进了并在代码里查找对CreateGraphics()的调用, 然后发现很多调用最后都没有销毁(Dispose)Graphics对象, 我就对这些调用进行修改, 或者增加Dispose()调用, 或者使用using代码块. 然后我就继续干别的去了.

几个星期后, 一个程序员来到我的办公桌旁, 说他发现了一件奇怪的事情: 他在进行自动化测试的时候, 发现程序很奇怪的突然再也不崩溃了. 以前他进行测试的时候, 经常会得到一堆System.ComponentModel.Win32Exceptions 异常, 但现在, 那些异常突然的就蒸发没了.

......

 

我对WebMatrix的改造正好是使用到了Graphics对象, 用来计算字符串的宽度, 代码如下:

private Interop.SIZE MeasureString(char[] chars, int startIndex, int length) 

    IntPtr fontPtr = this.Font.ToHfont(); 
    Graphics graphics = Graphics.FromHwnd(IntPtr.Zero); 
    IntPtr hdc = graphics.GetHdc(); 
    Interop.SelectObject(hdc, fontPtr); 
    Interop.SIZE size = this.MeasureString(hdc, chars, startIndex, length); 
    Interop.SelectObject(hdc, IntPtr.Zero); 
    graphics.ReleaseHdc(hdc); 
    graphics.Dispose(); 
    return size;

}

该函数调用频率很高, 而每次调用都会创建一个Graphics对象, 综合上面的那位国外同行的经验, 我怀疑是因为Graphics对象(或者是Hdc对象)创建数量过多, 而GC回收的速度赶不上创建的速度, 最终导致 .NET Framework 无法创建更多的Graphics对象(或者是Hdc对象)而报错. 如果真的是这样, 那么一个解决办法就是尽量少不创建新的Graphics对象(或者是Hdc对象).

为了验证, 我把该函数改成这样:

private Interop.SIZE MeasureString(char[] chars, int startIndex, int length) 

    Graphics g = this.CreateGraphics(); 
    SizeF s = g.MeasureString(new string(chars, startIndex, length), this.Font); 
    g.Dispose();

    Interop.SIZE size = new Interop.SIZE(); 
    size.x = (int)s.Width; 
    size.y = (int)s.Height;

    return size; 
}

 

再编译运行, 结果不管怎么折腾, 程序再也不会出现 "缓冲操作当前正在进行中,无法释放BufferedGraphicsContext" 这个奇怪的错误.

 

结论:

很有可能是因为Graphics对象(或者是Hdc对象)创建数量过多, 而GC回收的速度赶不上创建的速度, 最终导致 .NET Framework 无法创建更多的Graphics对象(或者是Hdc对象)而报错.

解决办法:

Graphics对象使用完毕后就调用Dispose销毁掉, 不要全部依赖GC的回收.

PS:

由于我本人水平有限, 研究得也不是很深入, 这个结论很可能不是完全正确的. 如果结论有错, 欢迎对这方面研究得比较深入的童鞋指出. 批评永远是欢迎的, 不欢迎"正面报道为主".

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是本人花费一定资金购买的倒立摆资料,和2013年电赛倒立摆配套!并且包含了阅读的软件。送给广大参赛学子,祝取得佳绩!如有侵权,请联系我删除,谢谢。 【作者基本信息】 天津理工大学, 控制理论与控制工程, 2007, 硕士 【摘要】 倒立摆是一个复杂的快速、非线性、多变量、强耦合、自然不稳定的非最小相位系统,是重心在上、支点在下控制问题的抽象。在对控制方法的研究过程,科研人员往往因为找不到合适的实际控制对象,而失去了对研究成果做进一步深入研究的条件,也给理论成果转化为实用成果造成障碍。倒立摆结构简单、成本较低,可以有效地检验众多控制方法的有效性。在各种类型的倒立摆,旋转倒立摆有其突出的优点,它是一个理想的控制理论研究平台,许多抽象的控制概念如系统稳定性、可控性、收敛速度和抗干扰能力等,都可以通过旋转倒立摆系统直观地表现出来。本文在深入研究旋转倒立摆系统结构原理和借鉴国内外该领域最新研究成果的基础上,对旋转倒立摆系统进行了建模分析和控制方法的研究。建立了旋转倒立摆系统的拉格朗日方程,经过在系统平衡点线性化之后,得到整个系统的状态方程描述。在采用LQR控制实现旋转倒立摆控制的基础上,将LQR控制和模糊控制结合起来,使它们相互协调配合,发挥各自的长处,进一步提高摆杆的稳定程度。经过实物控制,有效地改善旋转倒立摆的动态性能,提高了控制精度。设计BP网络,通过对控制样本的学习,实现对一级旋转倒立摆控制器的逼近。仿真结果表明,采用包含一个隐层的BP网络,适当选择隐层神经元个数,选择合理的网络模型参数和样本,可实现对一级旋转倒立摆控制器较好的逼近。最后,探讨了模糊控制和神经网络控制相结合,吸取两者的长处,实现旋转倒立摆控制的途径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值