Важное предварительное замечание: отладчик Гедымина вносит существенные искажения в исходный код скрипт-функций из-за чего сборка мусора может работать не так, как ожидает этого программист, и не так, как она будет работать в режиме без отладочной информации. Всегда проверяйте код в режиме без отладки перед передачей в промышленную эксплуатацию.
Особенности классов VBScript
- Событие Terminate вызывается только в процессе удаления из памяти последнего экземпляра данного класса.
- Наличие кольцевых ссылок, в т.ч. цепочек кольцевых зависимостей любой длины, приведет к тому, что ни один из экземпляров не будет удален сборщиком мусора и останется в памяти до конца работы программы.
Как мы столкнулись с проблемой неудаления объектов из памяти
В одной из задач с помощью TCreator создавалось модальное окно, которое оставалось на экране в течение всей рабочей смены. Оператор взаимодействаовал с окном сотни раз вызывая различные функции приложения. В процессе выполнения каждой функции выделялись ресуры (транзакции, запросы к базе данных и т.п.). Ресурсы не удалялись по завершении функции, так как локальный TCreator не уничтожался сборщиком мусора из-за наличия TCreator в месте создания модального окна. В конце концов исчерпывалась доступная оперативная память и приложение завершалось с ошибкой.
Возникает вопрос, как бороться с вышеуказанной частной ситуацией и как правильно работать с классами VBScript, чтобы максимально обезопасить себя от утечек памяти?
Использовать Designer.CreateObject -- Designer.DestroyObject
В описанном выше примере программист изначально понимает, что созданный экземпляр TCreator будет существовать до закрытия модального окна, а значит будет удерживать все последующие TCreator. В данном случае можно предложить решение с выделением и уничтожением ресурсов напрямую через глобальный объект Designer.
Создать копию класса TCreator
Вы автор подсистемы на платформе Гедымин. Код протестирован на корректную работу с ресурсами. Но, как обезопасить себя от ситуации, когда другая подсистема создаст долгоживущий TCreator и заблокирует все ваши механизмы очистки памяти?
Следует создать полную копию класса TCreator в рамках своей подсистемы и использовать ее для выделения ресурсов.
А надо ли каждый раз выделять-уничтожать ресуры?
В указанном выше приложении сотни раз за рабочую смену выделялись и уничтожались одни и те же ресурсы -- транзакции и запросы к базе данных. Одно из решений -- пул ресурсов. Нужные объекты создаются единожды и привязываются к окну (у нас есть соответствующее свойство Objects у формы). Остается только стартовать/комитить транзакции в нужных местах и выполнять/закрывать запросы к базе данных, без уничтожения самих объектов.
Альтернативный вариант в случае с экранной формой -- не создавать объекты для пула из программного кода, а просто разместить соответствующие компоненты на форме и обращаться к ним через метод GetComponent.
Принудительно уничтожить ресурсы в TCreator
В крайнем случае, ресуры выделенные через TCreator можно уничтожить принудительно, вызвав метод DestroyAllObjects. Теперь, даже если сборщик мусора не сможет удалить экземпляр TCreator, то в памяти останется только он, но не связанные с ним ресурсы.
Уничтожать TCreator как можно раньше
Стандартная практика -- TCreator уничтожается по завершении функции или процедуры. Если код процедуры или функции объемный и ресурсы нужны только в одной его части, то рекомендуется уничтожать экземпляр TCreator вручную, присваивая переменной значение Nothing.
Комментариев нет:
Отправить комментарий