VBScript. Использование TCreator
Бережное отношение к ресурсам компьютера – неприменный атрибут качественной программы. Сегодня, когда 1 Гб оперативной памяти на рабочей станции обычное дело, а операционные системы не имеют таких жестких ограничений на количество внутренних объектов, которые присутствовали во времена Windows 9х, многие разработчики не уделяют должного внимания вопросам экономного создания и удаления объектов. Как результат, приложение, вроде бы неплохо работающее на настольном компьютере, не запускается на POS терминале, оснащенном 128 Мб ОЗУ. Едва заметные утечки памяти могут привести к фатальным последствиям, если пользователь не выключает компьютер на протяжении нескольких дней или использует приложение особенно интенсивно. Многочисленные одновременные подключения к базе данных из программ, небрежно обращающихся с такими объектами, как транзакция или запрос, способны поставить в затруднительное положение даже очень производительный сервер.
Следует создавать объекты по мере необходимости и уничтожать их незамедлительно, по окончании использования. Исключением является ситуация, когда многократное создание и удаление объекта влекут значительные временные затраты. В этом случае можно рекомендовать использование глобальной переменной или пула объектов.
Программируя на Гедымине мы имеем дело с объектами трех видов:
- Экземпляры VBScript классов, созданные оператором New.
- COM объекты автоматизации (ActiveX объекты), созданные функцией CreateObject.
- Объекты платформы Гедымин, созданные вызовом метода Designer.CreateObject.
Для первых двух в среде выполнения VBScript действует автоматическая сборка мусора. Как только исчезает необходимость в объекте – он уничтожается. Как правило, это происходит по выходу из процедуры или функции, в рамках которой был создан объект. Программист имеет возможность форсировать данный процесс, присвоив значение Nothing соответствующей локальной переменной. С последними -- дело обстоит сложнее. Поскольку создаются они внутри платформы и не являются COM объектами, VBScript не может ни контролировать их использование, ни самостоятельно их удалять. Такая обязанность всецело возлагается на программиста.
Казалось бы, чего проще: Designer.CreateObject-Designer.DestroyObject – и все дела (см. пример ниже).
Dim Obj Set Obj = Designer.CreateObject(...) ... Designer.DestroyObject(Obj)
Однако, если мы не используем режим On Error Resume Next, то любая ошибка в процессе выполнения приведет к преждевременному выходу из тела процедуры. Строка кода Designer.DestroyObject выполнена не будет и объект останется в памяти до завершения выполнения программы. Ниже приведен пример такой, небезопасной функции. Ее задача – вернуть наименование контакта по заданному идентификатору. Если внутри функции произойдет ошибка (например, на вход будет передана строка буквенных символов вместо целочисленного идентификатора), то объект TIBSQL, сохраненный в переменной q, уничтожен не будет.
Function UnSafe_GetContactName(ID)
Dim q
Set q = Designer.CreateObject(nil, "TIBSQL", "")
q.Transaction = gdcBaseManager.ReadTransaction
q.SQL.Text = _
"SELECT name FROM gd_contact WHERE id=" & CLng(ID)
q.ExecQuery
UnSafe_GetContactName = q.Fields(0).AsString
Designer.DestroyObject(q)
End Function
К счастью, разработчики платформы нашли элегантное решение данной проблемы. Как отмечалось выше, локальные VBScript объекты автоматически уничтожаются при выходе из процедуры или функции. Был создан вспомогательный класс TCreator, который хранит список созданных объектов и уничтожает их в деструкторе. Теперь мы можем сделать безопасной нашу функцию:
Function Safe_GetContactName(ID) Dim Creator, q Set Creator = New TCreator Set q = Creator.GetObject(nil, "TIBSQL", "") q.Transaction = gdcBaseManager.ReadTransaction q.SQL.Text = _ "SELECT name FROM gd_contact WHERE id=" & CLng(ID) q.ExecQuery Safe_GetContactName = q.Fields(0).AsString End Function
От своего небезопасного аналога данная функция отличается лишь тем, что мы добавили переменную Creator и создаём объект через метод Creator.GetObject вместо Designer.CreateObject. Обратите внимание, что мы не удаляем Creator непосредственно -- об этом позаботится VBScript.
Класс TCreator входит в пакет Общие данные.