Есть ли необходимость устанавливать Object в Nothing внутри функций VBA - PullRequest
60 голосов
/ 05 февраля 2009

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

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

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

Set db = Nothing
Set record_set = Nothing

Ответы [ 7 ]

71 голосов
/ 05 февраля 2009

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

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

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

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

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

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

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

14 голосов
/ 05 февраля 2009

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

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

12 голосов
/ 06 февраля 2009

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

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

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

Имея это в виду, в этой статье из базы знаний Майкрософт, озаглавленной «Как предотвратить раздувание базы данных после использования объектов доступа к данным (DAO)», говорится, что вам следует явно закрыть, если вы не Я не хочу, чтобы ваши базы данных распухли. Вы заметите, что статья немного расплывчата в деталях; раздел «Причина» неясен, почти до абсурда.

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

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

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

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

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

2 голосов
/ 09 августа 2016

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

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

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

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

2 голосов
/ 05 февраля 2009

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

1 голос
/ 26 мая 2010

Я обычно всегда ставлю это в конце своих процедур или вызываю подпрограмму «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 голосов
/ 24 января 2013

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

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