Есть ли необходимость устанавливать для объектов ничего в функциях VBA

52

Я всегда читал, что рекомендуется устанавливать объекты на ничего, как только я закончил с ними. Но я обычно использую их только в функциях внутри форм.

Не потеряна ли ссылка и память, когда остается область действия, независимо от установки объектов на "Нет"?

то есть. это действительно необходимо сделать:

Set db = Nothing
Set record_set = Nothing
Теги:
ms-access
access-vba
office-2003

7 ответов

58
Лучший ответ

VB использует так называемый сборщик мусора "подсчет ссылок".

В принципе, в момент, когда переменная выходит за пределы области действия, счетчик ссылок на указанном объекте уменьшается. Когда вы назначаете ссылку на объект другой переменной, счетчик ссылок увеличивается.

Когда счетчик достигнет нуля, объект готов к сбору мусора. Ресурсы объекта будут выпущены, как только это произойдет. Локальная переменная функции скорее всего будет ссылаться на объект, счетчик ссылок которого никогда не превышает 1, поэтому ресурсы объекта будут освобождены при завершении функции.

Установка переменной в Nothing - это способ явно уменьшить ссылочный счет.

Например, вы читаете в файле и устанавливаете переменную файлового объекта Nothing сразу после вызова ReadAll(). Файл дескриптора будет немедленно выпущен, вы можете потратить время на его содержимое.

Если вы не установите значение Nothing, дескриптор файла может быть открыт дольше, чем это необходимо.

Если вы не находитесь в ситуации "должен разблокировать ценный ресурс", просто позволить переменным выйти из области действия в порядке.

  • 15
    Хотя все, что вы пишете, верно (и хорошо сказано), вопрос помечен MS Access, что означает VBA. VBA в Access исторически имел проблемы с неправильным обновлением счетчиков ссылок, поэтому на практике рекомендуется явным образом очистить переменные объекта.
  • 4
    Я не знал, что существует какая-либо заметная разница между VBA и VB 6.0 в этом отношении. Я не могу поверить, что они написали новый сборщик мусора и новую среду выполнения VB только для MS Access.
Показать ещё 10 комментариев
12

Сбор мусора редко бывает совершенным. Даже в .NET есть моменты, когда вам настоятельно рекомендуется запрашивать систему для сбора мусора раньше.

По этой причине я явно и закрываю и устанавливаю в записи Nothing, когда я с ними закончил.

  • 3
    Вы имеете в виду, что сборка мусора .NET не идеальна в том смысле, что ее дизайн не всегда оптимален или что в дизайне есть ошибки? И есть ли у вас какие-либо ссылки, объясняющие обстоятельства, при которых вам советуют провести ранний сбор? Благодарю.
  • 1
    Однажды студент пришел на Луну и сказал: «Я понимаю, как сделать лучший сборщик мусора. Мы должны вести подсчет указателей для каждого минуса ». Мун терпеливо рассказал студенту следующую историю:« Однажды студент пришел на Луну и сказал: «Я понимаю, как сделать лучший сборщик мусора ...
Показать ещё 3 комментария
9

Самая последняя строка раздела справки для Recordset.Close" в справке Microsoft DAO и в Справочнике разработчиков Access:

"Альтернативой методу Close является для установки значения переменной объекта в Nothing (установите dbsTemp = Nothing).

http://msdn.microsoft.com/en-us/library/bb243098.aspx

С учетом этого в этой статье из базы знаний Microsoft, озаглавленной "Как предотвратить раздувание базы данных после использования объектов доступа к данным (DAO)", говорит вам, что вы должны явно закрыть, если вы не хотите, чтобы ваши базы данных раздувались. Вы заметите, что статья немного расплывчата в деталях; раздел "Причина" неясен, почти до такой степени, что он является тарабарщиной.

http://support.microsoft.com/kb/289562

СИМПТОМЫ: база данных Microsoft Access начал раздуваться (или быстро расти размер) после внедрения Data Access Объекты (DAO), чтобы открыть набор записей.

ПРИЧИНА: Если вы не каждый раз, когда вы цикл через код набора записей, DAO может перекомпилировать, используя больше памяти и увеличивая размер базы данных.

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ: Когда вы создаете Объект Recordset (или QueryDef) в код, явно закрыть объект, когда вы закончили. Microsoft Access автоматически закрывает Recordset и Объекты QueryDef в большинстве обстоятельства. Однако, если вы явно закрыть объект в вашем кода, вы можете избежать случайных случаях, когда объект остается открыто.

Наконец, позвольте мне добавить, что я работаю с базами данных Access в течение 15 лет, и я почти всегда позволяю моим локально объявленным переменным набора записей выйти из области действия без явного использования метода Close. Я не проводил никаких испытаний, но это, похоже, не имеет значения.

2

Когда вы используете ASP classic (скрипты на стороне сервера), импортировать все объекты нечего, когда вы с ними работаете, потому что они не выходят за пределы области действия до тех пор, пока [виртуальный] сервер не будет закрыт.

По этой причине все примеры сценариев MS VB всегда показывали закрытые объекты и ничего не задавали. Чтобы фрагменты script можно было использовать в таких средах, как ASP classic, где объекты не выходили за рамки.

Редки случаи, когда вы хотите кодировать длительные процессы, в которых объекты не выходят за пределы области видимости, и вы обнаруживаете, что у вас закончилась физическая память, если вы явно не освобождаете объекты.

Если вы обнаружите, что кодирование ASP classic или запуск процессов в глобальной области по какой-либо другой причине, то да, вы должны явно освобождать объекты.

2

Предполагается, что ссылки очищаются, когда переменная выходит за рамки. Предположительно, это улучшилось с более поздними версиями программного обеспечения, но оно в свое время не было надежным. Я считаю, что остается хорошей практикой явно устанавливать переменные в "Nothing".

1

Обычно я всегда ставил это в конце моих процедур или вызывал его с помощью "CloseRecordSet", если я использую модули уровня:

Private Sub Rawr()
On Error GoTo ErrorHandler

    'Procedural Code Here.

    ExitPoint:
        'Closes and Destroys RecordSet Objects.
        If Not Recset Is Nothing Then
            If Recset.State = 1 Then
                Recset.Close
                Conn.Close
            End If
            Set Recset = Nothing
            Set Conn = Nothing
        End If
        Exit Sub

    ErrorHandler:
        'Error Handling / Reporting Here.
        Resume ExitPoint
End Sub

Таким образом, процедура заканчивается (обычно или из-за ошибки), объекты очищаются и ресурсы свободны.

Выполнение этого способа вполне безопасно, поскольку вы можете просто пощекотать его, и он будет делать только то, что необходимо для закрытия или уничтожения объекта набора записей/соединения, если он уже закрыт (из-за ошибка времени выполнения или просто закрытие его на ранней стадии, как это должно быть, просто убедитесь, что).

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

  • 0
    Это код ADO, нет? В наборах записей ADO отсутствует свойство State, и вы не используете объекты подключения. У ADO нет проблемы с подсчетом ссылок, как у DAO, поэтому вам не нужно очищать ее после. В любом случае, вы не должны использовать ADO в приложении Access - вне ADP, DAO является предпочтительной библиотекой доступа к данным, за исключением нескольких вещей, которые ADO делает лучше.
  • 0
    Он объявлен как ADODB.Recordset и имеет свойство состояния, которое определяет, открыто ли оно в данный момент или нет. По сути, он проверяет, установлено ли для него значение Nothing, а если нет, то сначала проверяет, открыт ли он по-прежнему (и закрывает ли, если нет), используя свойство состояния, а затем после него устанавливает его в ничто. Это полностью гарантирует, что оно полностью и чисто закрыто и может использоваться в любое время в рамках процедуры, независимо от того, открыт ли набор записей или нет, ничего или нет.
Показать ещё 1 комментарий
0

Попробуйте это

If Not IsEmpty(vMyVariant) Then
    Erase vMyVariant
    vMyVariant = Empty
End If

Ещё вопросы

Сообщество Overcoder
Наверх
Меню