GDI 中随机发生 AccessViolationException;
我们遇到的问题是,有时会出现 AccessViolationException
,并且会绘制一个简单的组框,背景为白色,顶部有一个红叉。我们无法可靠地重现此错误,它只是不时发生。
我们没有做任何特殊的事情,我们只是显示一个主窗口,其中包含菜单、工具栏、主面板上的组框以及组框内的一些超链接控件。
从堆栈跟踪来看,这似乎是 Windows 窗体或 GDI+ 中的错误:
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at System.Drawing.SafeNativeMethods.Gdip.GdipDrawLineI(HandleRef graphics, HandleRef pen, Int32 x1, Int32 y1, Int32 x2, Int32 y2)
at System.Drawing.Graphics.DrawLine(Pen pen, Int32 x1, Int32 y1, Int32 x2, Int32 y2)
at System.Windows.Forms.GroupBox.DrawGroupBox(PaintEventArgs e)
at System.Windows.Forms.GroupBox.OnPaint(PaintEventArgs e)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.GroupBox.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.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
We've got the problem that sometimes an AccessViolationException
occurs and a simple group box gets drawn with white background and a red cross on top of it. We can't reproducable this bug reliably, it just occurs from time to time.
We don't do anything special, we're just showing a main window with a menu, toolbar, the group box on the main panel and some hyperlink controls inside the group box.
From the stack trace it seems to be a bug in Windows Forms or GDI+:
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at System.Drawing.SafeNativeMethods.Gdip.GdipDrawLineI(HandleRef graphics, HandleRef pen, Int32 x1, Int32 y1, Int32 x2, Int32 y2)
at System.Drawing.Graphics.DrawLine(Pen pen, Int32 x1, Int32 y1, Int32 x2, Int32 y2)
at System.Windows.Forms.GroupBox.DrawGroupBox(PaintEventArgs e)
at System.Windows.Forms.GroupBox.OnPaint(PaintEventArgs e)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.GroupBox.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.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在 Dot.Net 中,作为内存优化或碎片整理过程的一部分,GC 将对象从一个位置移动到另一个位置。当将托管内存数组(或图像)的引用发送到非托管代码段时,通常会发生这种情况。
数据被移动到不同的位置,并且由于非托管代码不知道这一点,因此它尝试访问数据的“旧”位置。这只发生在发布模式下,因为在调试模式下内存优化已关闭,因此始终在发布模式下进行调试,嗯...
不幸的是,没有办法关闭 GC 碎片整理过程。
您可以尝试调用 GC.Collect() 并等待其完成,然后再调用 GDI+ 函数,但这只会改善情况并不能完全解决问题。
我能够绕过这个问题的唯一方法是手动锁定(固定)数据并在从非托管代码返回后释放它,是的,返回到 C++。图像很棘手,因为您需要找到所有类和子类中数据的准确引用。
In Dot.Net objects are moved by the GC from one place to the other as part of memory optimization or Defragmentation process. This usually happens when sending a reference of a managed memory array (or image) to an un-managed piece of code.
The data is being moved to a different location and as the un-managed code is not aware of this it tries to access the "old" location of the data. This only happens in Release mode as in Debug mode memory optimization is switched off so ALWAYS debug in Release mode, meh...
Unfortunately, there is no way to turn off the GC defragmentation process.
You can try and call the GC.Collect() and wait for it to finish before calling your GDI+ function but this will only improve the situation and not solve it completely.
The only way I was able to bypass this is to manually lock (pin) the data and release it after returned from the un-managed code, yes, back to C++. Images are tricky as you need to find the exact reference to the data in all the classes and sub-classes.
在所有内容发布之前,您是否调用过 GdiplusShutdown ?我在此处提出了类似的问题,我称之为GdiplusShutdown 在我的位图被破坏并且还出现访问冲突之前
Did you call GdiplusShutdown before everything was released? I asked a similar question here where I called GdiplusShutdown before my Bitmap was destroyed and also got access violation