Существует несколько проблемных областей, связанных с управлением памятью в VB6.
Первыми являются циклические ссылки, где дочерний класс указывает на родителя и наоборот. Без явной установки ссылки на Nothing, это иногда верно и для форм, особенно для диалога, являющегося редактором целевого объекта. Еще раз убедившись, что все установлено на ноль, решит проблему.
Основные принципы: 1) Если что-либо, на что указывает объект, является «живым», то оно не будет собирать мусор. Поэтому, когда вы устанавливаете ссылку на родительский объект циклической ссылки, дочерний объект является живым, поэтому родительский объект не получает сборщика мусора, поскольку родительский объект все еще жив, дочерний элемент не получает сборщик мусора.
То же самое с формами. Если вы не установите свойство Target в диалоговом окне, в котором редактирование объекта равно нулю, оно не будет запускать финальную серию событий, пока целевой объект активен.
Наиболее распространенными побочными эффектами этого является то, что ваше приложение не будет корректно завершать работу и объем памяти будет увеличиваться по мере использования приложения.
Что касается утечек GDI, каждый раз, когда вы используете внешнюю DLL, которая использует дескрипторы, указатели. Вы помещаете себя в ту же область, что и C ++ для этих функций. Поэтому вы должны убедиться, что вы следуете всем правилам конкретного API или DLL, которые вы используете, что часто включает в себя явное уничтожение того, что вы создали после того, как с ним покончено.
Существует элегантное решение проблемы циклических ссылок. Вместо того, чтобы ребенок ссылался на родителя напрямую, вы используете прокси.
Сначала создайте прокси-класс для родительского объекта.
Option Explicit Public Event GetRef(ByRef RHS As MyObject)
Public Function GetMyObject() As MyObject
Dim Ref As MyObject
RaiseEvent GetRef(Ref)
Set GetMyObject = Ref
End Function
Затем определите приватную переменную в Parent
Private WithEvents MyProxy As MyObjectProxy
Private Sub Class_Initialize()
Set MyProxy = New MyObjectProxy
End Sub
Затем настройте свойство только для чтения с именем Proxy и реализуйте событие GetRef.
Public Property Get Proxy() As MyObjectProxy
Set Proxy = MyProxy
End Property
Private Sub MyProxy_GetRef(RHS As MyObject)
Set RHS = Me
End Sub
Для ребенка или чего-либо еще, для чего нужна ссылка, код выглядит следующим образом.
Private ParentProxy As MyObjectProxy
Public Property Get Parent() As MyObject
If ParentProxy Is Nothing Then
Set Parent = Nothing
Else
Set Parent = ParentProxy.GetRef
End If
End Property
Public Property Set Parent(RHS As MyObject)
If RHS Is Me Then
Set MyObjectProxy = Nothing
ElseIf Target Is Nothing Then
Set MyObjectProxy = Nothing
Else
Set MyObjectProxy = RHS.Proxy
End If
End Property
Поскольку механизм событий не устанавливает ссылки или не увеличивает счетчик ссылок COM ни на один объект, он избегает всей проблемы циклических ссылок, которая является проблемой многих программистов VB6.
Примечание: источник, из которого я получил его, назвал его Прокси, но благодаря комментарию Энтони я считаю, что он также соответствует определению паттерна посредника. Он использует особую функцию VB6 Centric; API событий, который не совсем в духе паттерна посредника.
Также следует понимать, что .NET Framework имеет эквиваленты к API событий VB6, хотя он реализован по-другому (делегаты и т. Д.)