|
#1
|
||||
|
||||
Память и OPC
Нужно ли уничтожать объекты (.NET - технологией не пользуюсь, "уборки мусора" нет) возвращенные интерфейсами OPC (IOPCServerList, IOPCBrowseServerAddressSpase и др.)? (Скорее всего нужно.) Данные функции возвращают IEnumString - его уничтожать надо? И какими функциями это делать? (Все возможные лучше с кратким описанием для чего ини нужны?) Я знаю одну (CoTaskMemFree - но для чего она и как её применять - не знаю). Кто занимался этой проблемой - помогите. Особенно заботят утечки памяти от IOPCSyncIO, IOPCAsyncIO - если клиент будет работать долго - то это опасно. (PResultList и т.д. как уничтожить?) (Как уничтожить возвращенные объекты IStrindList и IResultList и другие.)
Заранее спасибо за ответ. |
#2
|
|||
|
|||
Интерфейсы в Дельфи - это объекты с управляемым временем жизни.
То есть с переменными любого типа, отнаследованого от TInterface, Дельфи поступает так. 1) если в процедуре описана переменная интерфейсного типа, то перед первым оператором процедуры эта переменная получает значение Nil; 2) у каждого объекта, реализующего какой-нибудь интерфейс обязательно должны быть две функции - AddRef и Release. Как правило, объект при вызове AddRef должен увеличить внутренний счётчик, при вызове Release - уменьшить. Если при этом значение счётчика станет равным нулю, то объект вызывает свой деструктор. То есть правильно реализованый COM-объект сам следит за своим временем жизни. Теперь синтаксический сахар 3) если A - переменная интерфейсного типа, а Exp - некое выражение, вырабатывающее интерфейс (переменная или вызов функции), то за оператором присваивания Код:
A:=Exp; Код:
if A<>Nil then A.Release(); // этот код Дельфи добавляет сама A:=Exp; if A<>Nil then A.AddRef(); // этот код Дельфи добавляет сама 5) кроме того, если в Record-е есть поля интерфейсного типа, то инициализация и финализация применяется и к ним. Что бы избавиться от интерфейса, достаточно переменной присвоить nil. То есть если не использовать явные приведения к Pointer и не использовать move и ему подобные ухищрения, то Дельфи всё сделает за Вас. Удачи |
#3
|
||||
|
||||
Код:
IInterface = interface ['{00000000-0000-0000-C000-000000000046}'] function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; end; IUnknown = IInterface; Пишу программы за еду. __________________ |
#4
|
||||
|
||||
Еще раз спасибо отвившим, эта тема очень вскользь описана и ответов я пока не нашёл. В общем, как я понимаю, для того, чтобы освободить память мне достаточно переменной интерфейсного типа присвоить nil? Остальное сделает сама Delphi?
Но я провёл эксперимент: procedure TForm1.FormCreate(Sender: TObject); var Mem : _MEMORYSTATUS; RetMem : Cardinal; //R:HRESULT; B:IOPCBrowseServerAddressSpace; Ser:IOPCServer; I:IDispatch; pEnum:IEnumString; S:String; pS,ItemID : POleStr; L:Longint; begin //R := CoInitializeEx(nil,COINIT_APARTMENTTHREADED); //OutputDebugString(PChar(Format('%d',[R]))); GlobalMemoryStatus(Mem); RetMem := Mem.dwAvailVirtual; OutputDebugString(PChar(Format('Свободная память: %d',[RetMem - Mem.dwAvailVirtual]))); //CoGetMalloc(1, Ser); Ser:=CreateComObject(ProgIDToClassID('dOPCSim.Kass l.Simulation')) as IOPCServer; GlobalMemoryStatus(Mem); OutputDebugString(PChar(Format('Память после создания сервера: %d',[RetMem - Mem.dwAvailVirtual]))); (*Ser.QueryInterface(IID_IOPCBrowseServerAddressSp ace,B); GlobalMemoryStatus(Mem); OutputDebugString(PChar(Format('Память после создания В: %d',[RetMem - Mem.dwAvailPhys]))); B.BrowseOPCItemIDs(OPC_BRANCH{OPC_LEAF},'',VT_EMPT Y,0,pEnum); GlobalMemoryStatus(Mem); OutputDebugString(PChar(Format('Память после создания перечисления: %d',[RetMem - Mem.dwAvailPhys]))); //OutputDebugString(PChar(Format('%d',[R]))); //CoTaskMemFree(pEnum); {pEnum.Next(1,pS,@L); S := pS; OutputDebugString(PChar(Format('%s : %d',[S,L]))); B.GetItemID(pS,ItemID); OutputDebugString(PChar(Format('%s',[ItemID]))); pEnum.Next(1,pS,@L); S := pS; OutputDebugString(PChar(Format('%s : %d',[S,L]))); B.GetItemID(pS,ItemID); OutputDebugString(PChar(Format('%s',[ItemID])));} B := Nil;*) { CoGetMalloc(1, cntMalloc); if Assigned(ppServerStatus.szVendorInfo) then cntMalloc.Free(ppServerStatus.szVendorInfo); if Assigned(ppServerStatus) then cntMalloc.Free(ppServerStatus);} //Ser.; Ser := Nil; GlobalMemoryStatus(Mem); OutputDebugString(PChar(Format('Память в конце: %d',[RetMem - Mem.dwAvailVirtual]))); //CoUninitialize; end; Ипри завершении процедуры последний вызов GlobalMemoryStatus(Mem) не даёт нуля. Хотя переменной Ser я вроде бы nil присвоил. Пытался насыльно вызвать Ser._Release но добился исключения и завершения по ошибке. Короче мож я не то делаю, или ошибочно понимаю технологию создания и освобождения. Да первоначально вопрос был другой, о результатах вызова этих функции, и и от самих одъектов типа OPC сервера память надо освобождать, ибо они больщие (сотни килобайт). Короче я запутался... |
#5
|
||||
|
||||
Код, что я отправил - работаюший. Но двихок сервера его изменил и сделал неверным, по этому я его отправляю еще раз...
Код:
procedure TForm1.FormCreate(Sender: TObject); var Mem : _MEMORYSTATUS; RetMem : Cardinal; //R:HRESULT; B:IOPCBrowseServerAddressSpace; Ser:IOPCServer; I:IDispatch; pEnum:IEnumString; S:String; pS,ItemID : POleStr; L:Longint; begin //R := CoInitializeEx(nil,COINIT_APARTMENTTHREADED); //OutputDebugString(PChar(Format('%d',[R]))); GlobalMemoryStatus(Mem); RetMem := Mem.dwAvailVirtual; OutputDebugString(PChar(Format('Свободная память: %d',[RetMem - Mem.dwAvailVirtual]))); //CoGetMalloc(1, Ser); Ser:=CreateComObject(ProgIDToClassID('dOPCSim.Kassl.Simulation')) as IOPCServer; GlobalMemoryStatus(Mem); OutputDebugString(PChar(Format('Память после создания сервера: %d',[RetMem - Mem.dwAvailVirtual]))); (*Ser.QueryInterface(IID_IOPCBrowseServerAddressSpace,B); GlobalMemoryStatus(Mem); OutputDebugString(PChar(Format('Память после создания В: %d',[RetMem - Mem.dwAvailPhys]))); B.BrowseOPCItemIDs(OPC_BRANCH{OPC_LEAF},'',VT_EMPTY,0,pEnum); GlobalMemoryStatus(Mem); OutputDebugString(PChar(Format('Память после создания перечисления: %d',[RetMem - Mem.dwAvailPhys]))); //OutputDebugString(PChar(Format('%d',[R]))); //CoTaskMemFree(pEnum); {pEnum.Next(1,pS,@L); S := pS; OutputDebugString(PChar(Format('%s : %d',[S,L]))); B.GetItemID(pS,ItemID); OutputDebugString(PChar(Format('%s',[ItemID]))); pEnum.Next(1,pS,@L); S := pS; OutputDebugString(PChar(Format('%s : %d',[S,L]))); B.GetItemID(pS,ItemID); OutputDebugString(PChar(Format('%s',[ItemID])));} B := Nil;*) { CoGetMalloc(1, cntMalloc); if Assigned(ppServerStatus.szVendorInfo) then cntMalloc.Free(ppServerStatus.szVendorInfo); if Assigned(ppServerStatus) then cntMalloc.Free(ppServerStatus);} //Ser.; Ser := Nil; GlobalMemoryStatus(Mem); OutputDebugString(PChar(Format('Память в конце: %d',[RetMem - Mem.dwAvailVirtual]))); //CoUninitialize; end; |