没有 GDI 泄漏的 VB6 内存泄漏

Posted

技术标签:

【中文标题】没有 GDI 泄漏的 VB6 内存泄漏【英文标题】:VB6 Memory Leaks Without GDI Leaks 【发布时间】:2011-09-13 18:10:43 【问题描述】:

我发现的关于调试 VB6 代码中的内存泄漏的所有建议都集中在 GDI 泄漏上。然而,在我的情况下,有证据表明我没有 GDI 泄漏,但可能确实有内存泄漏。哪些可能是导致此类泄漏的原因,和/或可以帮助我确定导致此泄漏的程序部分的好工具?

【问题讨论】:

【参考方案1】:

不幸的是,VB6 没有足够的调试工具来检测对象泄漏。我通常使用几个辅助函数在每个类、表单或用户控件中自己实现实例簿记。基本模式是这样的

Private Const MODULE_NAME As String = "<<class_name_here>>"

#If DebugMode Then
    Private m_sDebugID          As String
#End If

#If DebugMode Then
    Private Sub Class_Initialize()
        DebugInstanceInit MODULE_NAME, m_sDebugID, Me
    End Sub
#End If

#If DebugMode Then
    Private Sub Class_Terminate()
        DebugInstanceTerm MODULE_NAME, m_sDebugID
    End Sub
#End If

帮助函数 DebugInstanceInit 生成下一个连续的 id 并将其分配给 m_sDebugID,然后将模块名称和 ObjPtr(Me) 存储在一个集合中,键入该 id。

帮助函数DebugInstanceTerm 使用m_sDebugID 作为键从集合中删除条目。

这样,在应用程序执行的每一刻,您都可以转储此实例集合并识别已分配但仍未终止的对象的计数和类型。如果连续打开和关闭表单会增加对象计数,则可能是由于循环引用(例如 collection->entries 和 entry->collection)而泄漏了对象。

大多数框架和其他语言都内置了这种簿记(至少在调试版本中),但不幸的是,VB6 对源代码元数据(MODULE_NAME、FUNC_NAME、LINE_NUMBER)和对象生命周期管理的支持很差。缺乏实现继承在这里也很痛苦。

【讨论】:

【参考方案2】:

通常,您必须注意循环引用。在 VB6 中,只要在某处引用对象,它就会一直保留在内存中。因此,如果您有一个对象类型变量作为表单的成员(例如),那么它将在内存中,直到该表单被终止(除非您明确地将其设置为 nother 当然)。而且这个参考链可能很深:

这里,FormA 将 ObjectB 和 ObjectC 保存在内存中:

FormA -> ObjectB -> ObjectC

你需要注意的是这样的:

FormA -> ObjectB ObjectC

ObjectB 具有对 ObjectC 的引用,而 ObjectC 具有对 ObjectB 的后向或父级引用。即使 FormA 被终止或以其他方式清除它对 ObjectB 的引用,ObjectB 和 ObjectC 也将永远存在并表示内存泄漏。

【讨论】:

【参考方案3】:

查找内存泄漏的好工具是 deleaker。你可以试试看。并检查一件事 - 是否仍然存在 GDI 泄漏。你一定要确定!

【讨论】:

以上是关于没有 GDI 泄漏的 VB6 内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

使用GDI时如何确定是否有内存泄漏

防止 WPF 中的内存泄漏

c++ 内存泄漏问题

MFC内存泄漏调试

如何检查 C++ 代码中的内存泄漏。有没有检查内存泄漏的免费工具[重复]

电脑内存泄漏是怎么回事