1 (изменено: JAEAEJ, 06-12-2014 14:37:45)

Тема: Не могу освободить память от созданного объекта.

Win7, TCS 6.3 (19103)

Макрос, в цикле создаёт 4 разных объекта , после выполнения
определённых действий удаляет их. Он выполняется для всех
выделенных записей, количество которых превышает 500.
Запускаю макрос, доходит до 443-ей записи и вываливается с
сообщением (файл s1.tif). Смотрим диспетчер задач. До запуска
макроса TCS_Аll занимал 82 100 Кб, а после отвала 131 132 КБ.
Теперь, после отвала, любое действие с TCS_Аll приводит к
появлению сообщения о превышении используемых ресурсов.
Приходится убивать TCS_Аll диспетчером.
Для проверки метода освобождения памяти написал тестовый
скрипт.

Sub FormMacro_Test(TCSActiveModule)
  LogObject.ScriptTimeOut = 0
  For i = 1 to 100
    Set TP = TCSActiveModule.Properties("NmkTechnology").AsIDispatch 'Перейдём на техпроцесс
pbStr = CSDN_DESEAN_Library.ShowProgressBarNote(pbStr, "Ждите ... обрабатывается "+cStr( i ) +"-я запись." +_
TP.Properties("NMK_NAME").DisplayText)
    Call TCSApp.DeleteModuleByUserModuleName("Nmks_UniqueName")    '_1
    TP.UserModuleName = "Nmks_UniqueName"                  '_2
    Call TCSApp.DeleteModuleByUserModuleName("Nmks_UniqueName")    '_3
    Set TP = Nothing
  Next
   Call TCSApp.ShowMessageBox("", "END") 
Call TCSApp.HideProgressMessage
Exit Sub

Смотрим диспетчер. Запускаю тест. До запуска 77 908 Кб,
после окончания 80 848 Кб. Т.е. сожрал 10 940 Кб и этот кусок
памяти остаётся занятым пока TCS_Аll находится в памяти.

Как правильно освобождать память от создаваемых объектов?

Post's attachments

s1.tif 52.23 Кб, 5 скачиваний с 2014-12-05 

You don't have the permssions to download the attachments of this post.

Re: Не могу освободить память от созданного объекта.

В данном случае достаточно просто

Sub FormMacro_Test(TCSActiveModule)
  LogObject.ScriptTimeOut = 0
  For i = 1 to 100
    Set TP = TCSActiveModule.Properties("NmkTechnology").AsIDispatch 'Перейдём на техпроцесс
  Next
   Call TCSApp.ShowMessageBox("", "END")
Call TCSApp.HideProgressMessage
Exit Sub

Освобождение пройдет само. Заморочки с  DeleteModuleByUserModuleName обычно нужны когда создается объект первого уровня от TCSApp, либо нужна вывести какой либо модуль в глобальную область.

Смотрим диспетчер. Запускаю тест. До запуска 77 908 Кб, после окончания 80 848 Кб.

Это не показатель конечно, но поизучаем, скорей всего в модуле ТП где-то утечки.

3 (изменено: JAEAEJ, 09-12-2014 12:36:42)

Re: Не могу освободить память от созданного объекта.

Заморочки с  DeleteModuleByUserModuleName

Согласен с Вами. Жаль, что нет функции FreeAndNil(), как в
Dedlphi.
Прогнал скрипт на 2200 записей - память увеличилась на ~24 Мб.
Пока это терпимо. Главное, чтобы скрипт не свалился.

в модуле ТП где-то утечки.

Похоже что в CSDNMain.bpl.

Re: Не могу освободить память от созданного объекта.

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

Метод  DeleteModuleByUserModuleName появился из-за того, что мы сделали часть объектов (обычно это первый уровень от TCSApp) глобальными, и после первого обращения к ним они не уничтожаются, а остаются в памяти. Это порой сильно упрощает написание кода. Однако пользователи стали этим злоупотреблять, производя кучу глобальных объектов типа Single... (порой совершенно излишне). Поэтому пришлось добавить такой метод, чтобы дать возможность удалять такие объекты.  Менять поведение нельзя, так как отвалятся ранее написанные программы.

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

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

Начиная с 6.3 любой глобальный модуль вы можете сделать обычным вот таким вызовом (пример)

Set M = TCSApp.Mesuriment
M.UserModuleName = M.UniqueUserModuleName
TCSApp.DeleteModuleByUserModuleName( M.UserModuleName )
i = M.ShowModal( "test" )

после уничтожения переменной M связанный с ней модуль так же уничтожится (до версии 6.3 модуль уничтожался сразу после вызова DeleteModuleByUserModuleName).

и все.

При работе со свойствами (то что у вас приведено в примере) или зависимыми объектами и прочими производными интерфейсами работа с  UserModuleName и DeleteModuleByUserModuleName совершенно не нужна и может только создать лишние проблемы (читай про создание своих глобальных объектов).