Динамическое распределение памяти в VB6 - PullRequest
2 голосов
/ 05 ноября 2008

Есть ли такая вещь?

Я говорю о чем-то вроде команды C ++ new, то есть выделении памяти, которая требует явного освобождения памяти (или риска утечки памяти).

Я спрашиваю, потому что я помню, как раньше решал некоторые проблемы с утечкой GDI, устанавливая формы / элементы управления / другие объекты на Nothing, но не могу вспомнить, что и почему сейчас ...

Нужно ли нам когда-нибудь беспокоиться об управлении памятью при разработке в VB6?

Ответы [ 3 ]

7 голосов
/ 05 ноября 2008

Существует несколько проблемных областей, связанных с управлением памятью в 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, хотя он реализован по-другому (делегаты и т. Д.)

3 голосов
/ 05 ноября 2008

Да, у меня были схожие проблемы с различными формами, поэтому при каждой выгрузке я устанавливал их явным образом.

Но проблемы, в которых в основном используются сторонние элементы управления, кажется, что иногда не все ссылки на COM очищаются правильно.

Взгляните здесь .

3 голосов
/ 05 ноября 2008

Я бы хотел сказать, что вам никогда не придется беспокоиться об управлении памятью, но это не совсем так. В какой-то степени это зависит от среды выполнения, в которой выполняется ваш код VB6. Я наверняка видел классы VB6, работающие под COM +, которые могли бы привести к утечке памяти, если бы они явно не устанавливали ссылки на объекты Nothing, когда с ними покончено.

Помимо экологических проблем, память, которую вы выделяете в системе типов VB6, как правило, будет очищена для вас. Я говорю о вещах, которые вы выделяете с помощью ключевого слова New. Но есть существенное исключение, на которое указывают rpetrich и другие: -

Из-за механизма подсчета ссылок, который VB использует для управления временем жизни выделенных объектов, возможна утечка памяти, если у вас есть какие-либо циклические ссылки. Например, A-> B-> C-> A. Если у вас есть такой сценарий, вам, вероятно, придется определить его самостоятельно и вылечить, явно указав ссылку на Nothing. Мне не известны какие-либо инструменты, которые могут помочь в выявлении подобных проблем.

Дальнейшие проблемы возникают, когда вы используете библиотеки, написанные на других языках. Вы можете создать новый COM-объект, написанный на C ++, который выделяет часть памяти для себя, и обнаружить, что вам нужно вызвать определенный метод (например, Close), чтобы освободить эту память. Может быть, такой COM-объект был бы плохо написан, но их много.

Так что нет никаких правил, за исключением, возможно, следующих: -

  1. Постарайтесь узнать как можно больше о поведении любых библиотек, которые вы используете, и
  2. Всегда выполняйте свой код, наблюдая за трассировкой памяти в системном мониторе, чтобы убедиться, что использование памяти не растет неограниченным образом.
  3. Постарайтесь знать о циклических ссылках; -)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...