创建窗口句柄时出错(VB.NET)

创建窗口句柄时出错(VB.NET),vb.net,memory-leaks,memory-profiling,Vb.net,Memory Leaks,Memory Profiling,我有一个用VB.NET编写的相当大的应用程序,它似乎受到了某种内存泄漏的影响。每天有好几次,这个应用程序的实例似乎随机崩溃,但总是在使用了将近一天之后崩溃。我已经搜索并阅读了许多论坛,甚至在Stack Overflow上提出了关于这个特定问题的问题。我确定这与内存泄漏有关,通常指向超过10000的句柄或超过限制的对象 我已经下载了memory pro filer,并用它来定位和修复程序中的几个内存泄漏,但这似乎并没有减缓每天的崩溃计数。我的程序使用一个全局错误捕捉器来记录这些事件,并将有关它们的

我有一个用VB.NET编写的相当大的应用程序,它似乎受到了某种内存泄漏的影响。每天有好几次,这个应用程序的实例似乎随机崩溃,但总是在使用了将近一天之后崩溃。我已经搜索并阅读了许多论坛,甚至在Stack Overflow上提出了关于这个特定问题的问题。我确定这与内存泄漏有关,通常指向超过10000的句柄或超过限制的对象

我已经下载了memory pro filer,并用它来定位和修复程序中的几个内存泄漏,但这似乎并没有减缓每天的崩溃计数。我的程序使用一个全局错误捕捉器来记录这些事件,并将有关它们的信息存储在数据库中。我现在已经得到了大约2个月的数据,但是错误消息并不能真正帮助我指明任何方向。我最近为这个全局错误捕获程序添加了记录应用程序的句柄的功能,到目前为止,它远远低于10000句柄阈值。通常低于1000

长话短说,我的问题是。是否有办法记录GDI对象计数,以便确定这是否导致程序崩溃?除了这两个“对象”之外,是否还有其他“对象”可能导致内存泄漏和崩溃?我可以如何记录它们

我已经尽可能多地阅读了,但我就是不能很好地理解这一点,所以我很感激你能给我的任何指导。这类问题似乎困扰着很多节目。希望有人能帮助我,这可以帮助其他人在未来

关于我的程序和环境的更多信息。它主要运行在Windows7 64位机器上,虽然有一些vista和XP机器,但它运行在.NET4.0Framework上。该项目由几百个专门为此项目构建的表单、类和自定义控件组成。我正在使用.NET内存探查器4.6检查内存泄漏。我在我的电脑上运行了我认为是最资源密集型的操作,打开了一个多小时,然后关闭了很多屏幕,压缩了GYS的数据,等等。在观察任务管理器句柄、线程、用户对象和GDI对象中的资源时,没有一个超过1000

以下是崩溃事件日志之一的副本:

Loaded Assembly:   GlobalFuncs, Version=1.0.3391.14822, Culture=neutral, PublicKeyToken=null
Loaded Assembly:   Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Loaded Assembly:   mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly:   MySql.Data, Version=6.5.4.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d
Loaded Assembly:   SQL Database, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Loaded Assembly:   System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly:   System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Loaded Assembly:   System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly:   System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly:   System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Loaded Assembly:   System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Loaded Assembly:   System.Management, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Loaded Assembly:   System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly:   System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly:   System.Speech, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
Loaded Assembly:   System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly:   System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Loaded Assembly:   System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

OS Name:           Microsoft Windows 7 Professional 
OS Version:        6.1.7601.65536
OS Platform:       x64
Physical Memory:   1.91GB / 3.90GB (Free / Total)
Virtual Memory:    1.66GB / 2.00GB (Free / Total)

Error Output:
System.ComponentModel.Win32Exception (0x80004005): Error creating window handle.
   at System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp)
   at System.Windows.Forms.Control.CreateHandle()
   at System.Windows.Forms.TextBoxBase.CreateHandle()
   at System.Windows.Forms.Control.get_Handle()
   at System.Windows.Forms.RichTextBox.get_TextLength()
   at System.Windows.Forms.TextBoxBase.AdjustSelectionStartAndEnd(Int32 selStart, Int32 selLength, Int32& start, Int32& end, Int32 textLen)
   at System.Windows.Forms.TextBoxBase.GetSelectionStartAndLength(Int32& start, Int32& length)
   at System.Windows.Forms.TextBoxBase.AppendText(String text)
   at SWOT.My.MyApplication.ShowDebugOutput(Exception ex)
   at SWOT.My.MyApplication.app_ThreadException(Object sender, ThreadExceptionEventArgs e)
   at System.Windows.Forms.Application.ThreadContext.OnThreadException(Exception t)
   at System.Windows.Forms.Control.WndProcException(Exception e)
   at System.Windows.Forms.Control.ControlNativeWindow.OnThreadException(Exception e)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(ApplicationContext context)
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()

唯一的另一个问题是,我的全局错误捕获程序在尝试加载时崩溃,因为它无法创建更多句柄,而我不知何故丢失了这些信息。但是,当它没有崩溃并且能够记录句柄计数时,它的数量非常低,低于1000。垃圾收集器是否在程序崩溃后立即释放大量资源,然后才能记录高句柄计数?我只是对我拥有的数据感到有点迷茫和困惑。

基于错误输出表明您拥有超过1GB的大量内存,并且错误消息是错误创建窗口句柄,我怀疑您的应用程序遇到了一个问题,没有释放句柄,而不是没有释放内存。无法释放句柄的最可能原因是使用P/Invoke调用。您只需在代码中搜索Declare和DllImport,查看是否实际使用了任何P/Invoke函数。如果是,则需要详细检查调用的每个函数,以及它是否通过IntPtr或a返回任何句柄。如果这些调用中的任何一个创建了句柄,特别是窗口句柄,通常缩写为hWnd,那么您需要验证代码是否释放了hWnd


如果未使用任何DllImport/p/Invoke代码,则很可能是通过托管代码(如创建新的System.Windows.Forms.Form或System.Windows.Forms.Control派生类)间接调用了一个DllImport/p/Invoke代码,该类也会创建窗口句柄,而不会对其调用Close或Dispose。还有其他创建句柄的方法,但我想到了这些方法。

我收到了相同的错误消息,但不确定到底是什么地方出了问题!,但我还是想分享它是如何解决的

我没有做任何特别的事情,但正如Scott所说,表单是通过创建一个新实例和form.show方法来调用的。当一个按钮从主表单单击时,我所做的不是通过单击事件打开表单,而是直接将导致错误的表单作为启动表单并尝试运行。。表单未加载,也没有错误消息!,我返回并再次将启动表单更改为主表单并运行,然后单击按钮,在没有任何错误消息的情况下加载表单,这真是一个奇迹


不知道背后发生了什么变化,但现在一切都好了

我应该补充一点,我可以使用Microsoft的性能计数器记录句柄计数。也就是说,['code']PerfCounter=PerformanceCounter[code]PerfCount.CategoryName=Process[code]PerfCount.CounterName=Handle Count[code]PerfCount.NextValueSor
我对格式不太了解,我想不知道如何使用迷你降价。LOL如果你的应用程序崩溃需要一天的时间,那么看一个小时当然不够长。很有可能您记录了错误的句柄计数器,但真正的句柄并不是那么容易找到。错误总是一样的,调用Controls.Clear或Controls.Remove/At,不处理删除的控件。您需要与用户交谈,只需让他为您运行任务管理器。另外,从中分配windows的堆是与桌面上运行的其他进程共享的资源。所以从技术上讲,有可能会有另外两个泄密者撞毁你。@HansPassant谢谢你的回复,Hans。我一直在观察我的任务管理器,检查我的性能计数器是否与任务管理器显示的匹配,并且每次都非常匹配。在任务管理器中是否有我没有注意到的另一个句柄计数器?我只是想确保我告诉用户看哪一个,并且他们看的是正确的。我还将尝试在我的机器上运行该程序几天。不幸的是,我可能不会像其他用户那样使用它。也许我会幸运地看到一些东西。请留下一条评论,解释为什么这个答案被否决了,这样我就可以知道我犯了什么错误,并为每个人改进答案!由于大部分是在VB.NET中自学的,我不太清楚返回IntPtr的win32函数是什么意思。我将在谷歌上搜索它,并尝试研究它。不确定是谁否决了你的答案,但我会听取你的意见,看看在我的特殊情况下有没有什么可以帮助我的。如果在某些方面有帮助的话,我一定会回来投票给你的答案。我可能需要一些建议来了解你要带我去哪里。因此,您要求我将代码中的IntPtr转换为safehandle派生类,以便MDA(特别是释放句柄失败的MDA)能够捕获该错误并向我报告?默认情况下,此特定MDA是否已处于活动状态,但除非句柄类型为safehandle,否则无法捕获这些错误?我不认为我在程序中显式调用了任何调用,但可能是间接调用的。我想我现在有点不知所措,但这就是我们学习游泳的方法,对吗?让我往后退。。。请参阅上面的修订答案。>我想我现在有点不知所措,但这就是我们学习游泳的方法,对吗?当然!真为你高兴!查看并获取关于P/Invoke和使用本机方法的更多一般信息。因此,我检查了我的代码,没有找到Declare、DllImport、IntPtr或hWnd的任何实例,也没有找到最后两个实例,因此我非常确定我在任何地方都使用托管代码,并且所有句柄都是间接创建的。我检查并发现我正在创建的许多控件的实例以前没有被处理或关闭,我在.NET内存分析器的帮助下修复了这些问题。在我来这里寻求更多帮助之前,这些都已经完成了。我想我只需要继续沿着这条路走下去,试着找到更多的漏洞??非常感谢。