(изменено: JAEAEJ, 6 декабря 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 Кб, 6 скачиваний с 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 Кб.

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

(изменено: JAEAEJ, 9 декабря 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 совершенно не нужна и может только создать лишние проблемы (читай про создание своих глобальных объектов).

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

Есть новости по утечке памяти?
Мне поставили задачу создать около 1500 расчетных документов

dim doc
CreateCalculateDocument = TCSApp.Inventory.CalculateDocuments.AddCalculateDocument(...)
set doc = TCSApp.Inventory.SingleCalculateDocFromID(CreateCalculateDocument)
doc.UserModuleName = doc.UniqueUserModuleName
TCSApp.DeleteModuleByUserModuleName(doc.UserModuleName)

без DeleteModuleByUserModuleName память быстро заканчивается, с конструкцией DeleteModuleByUserModuleName через 1100 операций вылетел макрос с недостатком системных ресурсов. Технолоджик по диспетчеру задач занимал 350Мб (еще создавалось по такой же схеме 1100 учетных документов приходных и 1100 расходных)

Версия 7.9.0.0(39705)

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

без DeleteModuleByUserModuleName память быстро заканчивается,

Да это произойдет в итоге

с конструкцией DeleteModuleByUserModuleName через 1100 операций вылетел макрос с недостатком системных ресурсо

А вот тут не должно быть. Мы и больше создаем. Хотя в даннмо случае даже он не нужен на самом деле (ибо все скорее всего есть в модуле где вы создаеет документ).
Но. если код небольшой- кидайте, посмотрим.

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

dim doc, i
for i = 1 to 2000
CreateCalculateDocument = TCSApp.Inventory.CalculateDocuments.AddCalculateDocument(...)
set doc = TCSApp.Inventory.SingleCalculateDocFromID(CreateCalculateDocument)
doc.UserModuleName = doc.UniqueUserModuleName
TCSApp.DeleteModuleByUserModuleName(doc.UserModuleName)
if CreateCalculateDocument <> -1 then Doc.ActionList.ActionByName("AcceptAction").Execute
next

1000 итераций сжирают примерно 20Мб
если к ним прилепить назначение штрих-кодов и создание Учетных документов, то процесс быстрее пойдет, но для исключения дополнительных ошибок в коде, по данному примеру уже видно, что память расходуется

После завершения макроса память освобождается, но мне нужно, чтобы освобождение памяти было внутри цикла

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

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

dim doc, i, inv
set inv = TCSApp.Inventory.CalculateDocuments
inv.BeginUpdate
for i = 1 to 2000
CreateCalculateDocument = inv.AddCalculateDocument(...)
if CreateCalculateDocument <> -1 then inv.ActionList.ActionByName("AcceptAction").Execute
next
inv.EndUpdate

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

Память расходуется так же, как и в моем примере

inv.ActionList.ActionByName("AcceptAction").Execute

Оприходует последний созданный документ, на котором курсор стоит? или все неоприходованные документы?

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

Память расходуется так же, как и в моем примере

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

Оприходует последний созданный документ, на котором курсор стоит

Да. Можно ИД конечно проверить для страховки, но поведение обычно такое.

Может конечно на 7.9.1 обновиться, там фиксы багов были, в том числе и с АПИ.