BSTR memory management
От: aLEXa123  
Дата: 13.08.02 08:35
Оценка:
for(int i=0; i < doXpeHaPA3; i++) {
 BSTR bstr;
 pBrowser->get_StatusText( &bstr );
 //SysFreeString( bstr ); // иначе leak??
}

Как определить утечку памяти в VC для такого блока? И будет ли утечка?
Re: BSTR memory management
От: Vi2 Удмуртия http://www.adem.ru
Дата: 13.08.02 08:57
Оценка: 1 (1)
Здравствуйте aLEXa123, Вы писали:

LEX>Как определить утечку памяти в VC для такого блока?


Не знаю возможно ли такое в принципе. Дело касается памяти, выделенной по SysAllocString.

LEX>И будет ли утечка?


А утечка будет, если метод завершится без ошибки.

IWebBrowser2::StatusText Property
Remarks
The WebBrowser object ignores this property.
The caller frees the pbstr buffer with the SysFreeString function.

Поэтому нужно использовать CComBSTR или обработку ошибок:
for(int i=0; i < doXpeHaPA3; i++) {
  CComBSTR bstr;
  pBrowser->get_StatusText( &bstr );
}
или
for(int i=0; i < doXpeHaPA3; i++) {
  BSTR bstr;
  if( SUCCEEDED(pBrowser->get_StatusText( &bstr )) )
    SysFreeString( bstr ); // иначе leak??
}
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[2]: BSTR memory management
От: aLEXa123  
Дата: 13.08.02 09:51
Оценка:
Ясно, а есть ли какое средство вроде CrtDumpMemoryLeaks() для определения утечек памяти в COM приложениях? Как "поймать" leak`и от пропущенных комманд Release() ?

for(int i=0; i < doXpeHaPA3; i++) {
  CComBSTR bstr;  //wrapper всегда удобен!
  SomeInterface *pInterface;
  pInterface->get_DeeplyHiddenText( &bstr );
  //что-то там замутили с pInterface
  //...
  //pInterface->Release(); 
  //pInterface = NULL;
}
Re[3]: BSTR memory management
От: Vi2 Удмуртия http://www.adem.ru
Дата: 13.08.02 09:57
Оценка:
Здравствуйте aLEXa123, Вы писали:

LEX>Ясно, а есть ли какое средство вроде CrtDumpMemoryLeaks() для определения утечек памяти в COM приложениях?


Я не знаю. Всё-таки это не "утечки" в обычной памяти задачи, которые можно "словить" в задаче. Есть такой интерфейс IMalloc и IMallocSpy, через которые реализованы SysAllocXXXX и т.д., но я ими не пользовался. Вроде как бы и незачем.

LEX>Как "поймать" leak`и от пропущенных комманд Release() ?


Никак. Это не лики. Это нормальное положение дел: клиент (какой-то) держит объект сервера. Может быть его уже и не существует, но для сервера картина не меняется.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[2]: BSTR memory management
От: dupamid Россия  
Дата: 13.08.02 09:57
Оценка:
Здравствуйте Vi2, Вы писали:

Vi2>Не знаю возможно ли такое в принципе. Дело касается памяти, выделенной по SysAllocString.


Судя по MSDN можно, так как SysAllocString внутри выделяется память через CoTaskMemAlloc (которя работате через IMalloc::Alloc), можно установить шпиона через CoRegisterMallocSpy (реализовав интерфейс IMallocSpy). Но надо учесть, что реализация строк кеширует память и поэтому отдает ее не сразу, так что определить утечку можно, но достаточно сложно.
Re[4]: BSTR memory management
От: aLEXa123  
Дата: 13.08.02 11:11
Оценка:
Вот фрагмент с консоли при пропущенном Release() Выходит, утечки памяти нет? Из описания IUnknown::Release следует,что он — decrements the reference count for the calling interface on a object. If the reference count on the object falls to 0, the object is freed from memory!?


QIThunk - 4 AddRef   :Object = 0x00d951c8 Refcount = 1    CSimpleAtlClass - ISimpleAtlClass
QIThunk - 3 Release  :Object = 0x00d951c8 Refcount = 0    CSimpleAtlClass - ISimpleAtlClass
QIThunk - 1 Release  :Object = 0x00d94ff8 Refcount = 0    CComClassFactory - IUnknown
ATL: QIThunk - 4 LEAK:Object = 0x00d951c8 Refcount = 1    MaxRefCount = 1    CImplementClass - ISomeInterface


Vi2>Никак. Это не лики. Это нормальное положение дел: клиент (какой-то) держит объект сервера. Может быть его уже и не существует, но для сервера картина не меняется.
Re[5]: Потери объектов
От: Vi2 Удмуртия http://www.adem.ru
Дата: 13.08.02 11:27
Оценка:
Здравствуйте aLEXa123, Вы писали:

LEX>Вот фрагмент с консоли при пропущенном Release() Выходит, утечки памяти нет? Из описания IUnknown::Release следует,что он — decrements the reference count for the calling interface on a object. If the reference count on the object falls to 0, the object is freed from memory!?


LEX>QIThunk - 4 AddRef   :Object = 0x00d951c8 Refcount = 1    CSimpleAtlClass - ISimpleAtlClass
LEX>QIThunk - 3 Release  :Object = 0x00d951c8 Refcount = 0    CSimpleAtlClass - ISimpleAtlClass
LEX>QIThunk - 1 Release  :Object = 0x00d94ff8 Refcount = 0    CComClassFactory - IUnknown
LEX>ATL: QIThunk - 4 LEAK:Object = 0x00d951c8 Refcount = 1    MaxRefCount = 1    CImplementClass - ISomeInterface


Вообщем, ситуация такова. Это не лики, это потеря объекта. А поскольку объект содержит некий объём памяти, и потеря памяти.

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

Если же сервер решил завершиться, невзирая на существование своих объектов, то в потере памяти виноват сервер, а не пропущенный Release(). Это случается при падении сервера и при нормальных клиентах. Опять же это не лики как таковые — дай возможность объектам завершиться и ликов не будет.

Есть средства, наподобие тех, которые ты показал. При условии, что клииентов действительно нет, а ссылки есть. А это известно только тестеру. ИМХО, программно это не определить — есть ли клиент вот для этого объекта сервера.
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[6]: Потери объектов
От: aLEXa123  
Дата: 13.08.02 12:00
Оценка:
Во как раз потерю обьекта и нужно определитЬ!
Решил попробовать такой код

ISimpleAtlClass -интерфейс к простейшему COM серверу, имеющему
 private:
 BSTR m_BSTR;   .//свойство
 int dummyIntArray[102400000]; //о**ительный массив, его инициализация сразу же будет "заметна" в Task MAnager ^)))


  CoInitialize(NULL);   
  try {
   ISimpleAtlClass *pI;
   HRESULT hr = CoCreateInstance(__uuidof(CSimpleAtlClass), NULL, CLSCTX_ALL, __uuidof(ISimpleAtlClass), (void**)&pI);
   OLECHAR FAR* bs = L"BSTRing";
   pI->put_bstr_Prop(bs);
   cout << "Ok, - "<< (LPCSTR)pI->Getbstr_Prop() << endl; 
   //pI->Release();      
  }catch (_com_error e)    {} 
  cout<<"exited try block, about to CoUnInitialize"<<endl;
  getchar();  // ЗДЕСЬ ОГРОМНОЕ КОЛИЧЕСТВО ПАМЯТИ НЕ ОСВОБОЖДЕНО
  CoUninitialize(); //а вот если "откомментить" Release, то все ок!
  return 0;

Конечно, мониторинг памяти через Task Manager эт моветон, но как иначе пока не понятно (( .
Re[4]: BSTR memory management
От: Lexey Россия  
Дата: 13.08.02 19:07
Оценка:
Здравствуйте Vi2, Вы писали:

Vi2>Здравствуйте aLEXa123, Вы писали:


LEX>>Ясно, а есть ли какое средство вроде CrtDumpMemoryLeaks() для определения утечек памяти в COM приложениях?


Vi2>Я не знаю. Всё-таки это не "утечки" в обычной памяти задачи, которые можно "словить" в задаче. Есть такой интерфейс IMalloc и IMallocSpy, через которые реализованы SysAllocXXXX и т.д., но я ими не пользовался. Вроде как бы и незачем.


В RSDN Magazine #0 была статья Влада про ловлю ликов с помощью IMallocSpy.

LEX>>Как "поймать" leak`и от пропущенных комманд Release() ?


Vi2>Никак. Это не лики. Это нормальное положение дел: клиент (какой-то) держит объект сервера. Может быть его уже и не существует, но для сервера картина не меняется.


Ну, вообще говоря, это вопрос определения. Я как-то привык такие вещи тоже считать разновидностью ликов.

P.S. А вообще, юзайте Bounds Checker — он рулит. Большинство утечек ловит на раз. В том числе и с SysAllocString. Правда все-таки не все.
Re[2]: BSTR memory management
От: Lexey Россия  
Дата: 13.08.02 19:10
Оценка:
Здравствуйте Vi2, Вы писали:

LEX>>И будет ли утечка?


Vi2>А утечка будет, если метод завершится без ошибки.


Vi2>IWebBrowser2::StatusText Property

Vi2>Remarks
Vi2>The WebBrowser object ignores this property.
Vi2>The caller frees the pbstr buffer with the SysFreeString function.

Я бы даже сказал безотносительно конкретного интерфейса. Если параметр [out], то утечка будет (при отсутствии ошибок). Если [in,out], то нет (кроме последней итерации цикла — здесь она тоже будет).
Re[3]: BSTR memory management
От: Vi2 Удмуртия http://www.adem.ru
Дата: 14.08.02 02:53
Оценка:
Здравствуйте Lexey, Вы писали:

L>Я бы даже сказал безотносительно конкретного интерфейса. Если параметр [out], то утечка будет (при отсутствии ошибок). Если [in,out], то нет (кроме последней итерации цикла — здесь она тоже будет).


Меня смутила немного фраза из MSDN: The WebBrowser object ignores this property.
Если он игнорирует, значит, вполне может возвращать код ошибки или возвращать NULL. Тогда освобождать-то и нечего, и ликов не будет.

А по большому счёту согласен. Правило хорошего программирования, однако, — подчищай за собой, не оставляй подчистку на систему или на перезагрузку!
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[7]: Потери объектов
От: Vi2 Удмуртия http://www.adem.ru
Дата: 14.08.02 03:20
Оценка:
Здравствуйте aLEXa123, Вы писали:

LEX>Во как раз потерю обьекта и нужно определитЬ! :)


А что её определять! Её и так видно. После создания объекта у него нужно в обязательном порядке уменьшить количество ссылок через Release().

LEX>Решил попробовать такой код


LEX>ISimpleAtlClass -интерфейс к простейшему COM серверу, имеющему

LEX> private:
LEX> BSTR m_BSTR; .//свойство
LEX> int dummyIntArray[102400000]; //о**ительный массив, его инициализация сразу же будет "заметна" в Task MAnager ^)))

Я так понимаю, что интерфейсы становятся известны у тебя в программе через #import. Тогда лучше пользоваться не интерфейсом ISimpleAtlClass, а его оболочкой ISimpleAtlClassPtr, которая будет подчищать за собой ссылки на объект.

LEX> //а вот если "откомментить" Release, то все ок!


Так естественно Release() нужно вызывать, если работаешь с указателем на интерфейс. Если работаешь с классами, скрывающими работу с указателем, то этот Release() они вызовут сами в деструкторе.

CoInitialize(NULL);
{ //Vi2-Эти скобки нужны для синхронизации жизни объекта pI и вызова CoUninitialize!
  ISimpleAtlClassPtr pI = NULL;
  try
  {
    //Vi2-Нужно использовать методы класса, чтобы создавать объект
    HRESULT hr = pI.CreateInstance(__uuidof(CSimpleAtlClass), NULL, CLSCTX_ALL);
    if( SUCCEEDED(hr) )
    {
      //Vi2-Нужно использовать имя свойства - функции будут автоматически вызваны.
      pI->bstr_Prop = L"BSTRing";
      cout << "Ok, - "<< (LPCSTR) pI->bstr_Prop << endl; 
    }
  }
  catch(_com_error e)
  {
  }
  cout<<"exited try block, about to CoUnInitialize"<<endl;
}
getchar();
CoUninitialize();
return 0;
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[8]: Потери объектов
От: aLEXa123  
Дата: 14.08.02 10:13
Оценка:
Чиерт побьери, всегда приятно побеседовать с грамотным человеком !
С вышеознач. примером все ясно — память освобождается после команды Release или выходе из try в деструкторе _com_ptr_t<>
Так как я сам создал простой COM-сервер, то с подсчетом его ссылок нет проблем.
Но на самом деле меня подтолкнул на все это пример с работой интерфейсов XML. (#import "msxml3.dll")
for(int i=0; i < MnogoElements; i++) {
 IXMLDOMNode *pNode = NULL;                     
 hr = pXMLSel->nextNode(&pNode);
 pNode->get_firstChild(&pNode); //из одного указателя "рожаем" второй (указ. на следующий узел)
 BSTR bStr;                  //теперь pNode указывает на следующий узел, а прежний указатель "утек"??
 pNode->get_text(&bStr);         
 lstrcpy(wdataPtr->stArtc, CW2A(bStr));
 ::SysFreeString(bStr); 
 //RELEASE(pNode);        //так утеря обьекта :-(, а если всетаки вызвать Release...
 pNode->get_nextSibling(&pNode); //то нельзя перейти к следующему узлу, ведь pNode = NULL 
 pNode->get_text(&bStr);
 lstrcpy(wdataPtr->stName, CW2A(bStr));        
 ::SysFreeString(bStr);                            
 //RELEASE(pNode); 
 pNode->get_nextSibling(&pNode); 
 pNode->get_text(&bStr);                                        
 lstrcpy(wdataPtr->stDesh, CW2A(bStr));  
 ::SysFreeString(bStr);
 RELEASE(pNode);
 wdataPtr++;                                
}

Без Release`ов код отлично работает, только программа нагло жрет память
Re[9]: Потери объектов
От: Vi2 Удмуртия http://www.adem.ru
Дата: 14.08.02 11:50
Оценка:
Здравствуйте aLEXa123, Вы писали:

LEX>Чиерт побьери, всегда приятно побеседовать с грамотным человеком !

LEX>С вышеознач. примером все ясно — память освобождается после команды Release или выходе из try в деструкторе _com_ptr_t<>
LEX>Так как я сам создал простой COM-сервер, то с подсчетом его ссылок нет проблем.
LEX>Но на самом деле меня подтолкнул на все это пример с работой интерфейсов XML. (#import "msxml3.dll")
LEX>[skipped]
LEX> IXMLDOMNode *pNode = NULL;
LEX> hr = pXMLSel->nextNode(&pNode);

LEX> //из одного указателя "рожаем" второй (указ. на следующий узел)

LEX> pNode->get_firstChild(&pNode);
LEX> //теперь pNode указывает на следующий узел, а прежний указатель "утек"??
LEX>
LEX> //RELEASE(pNode); //так утеря обьекта , а если всетаки вызвать Release...
LEX> pNode->get_nextSibling(&pNode); //то нельзя перейти к следующему узлу, ведь pNode = NULL

LEX>Без Release`ов код отлично работает, только программа нагло жрет память


Да потому что непутевый код, потому и работает! Это завсегда так.

Так или иначе, тебе нужно освобождать предыдущее значение pNode перед тем как в него запишешь другое значение. Например, переписав во временную переменную:
  IXMLDOMNode *pNodeTmp;
.....
  pNodeTmp = pNode;
  pNode->get_firstChild(&pNode);
  pNodeTmp->Release();


Если бы использовал ATL-ский CComPtr, то получил бы предупреждение при взятии & с непустым содержимым объекта!
Vita
Выше головы не прыгнешь, ниже земли не упадешь, дальше границы не убежишь! © КВН НГУ
Re[10]: Потери объектов
От: aLEXa123  
Дата: 14.08.02 19:44
Оценка:
Vi2>Да потому что непутевый код, потому и работает! Это завсегда так.
ЭЭЭ-т точно! (Сказал товарищь Сухов! )
Vi2>Так или иначе, тебе нужно освобождать предыдущее значение pNode перед тем как в него запишешь другое значение. Например, переписав во временную переменную:
Именно эт я и сделал! Пришлось "ввести" этой проге в одно место новый указ.- Node1!
for(int i=0; i < lvalue; i++) {
 IXMLDOMNode *pNode = NULL, *pNode1 = NULL;                     
 hr = pXMLSel->nextNode(&pNode);
 pNode->get_firstChild(&pNode1);
 RELEASE(pNode);         // старый pNode удаляется нах**!                        
 BSTR bStr;         
 pNode1->get_text(&bStr);
 lstrcpy(wdataPtr->stArtc, CW2A(bStr));
::SysFreeString(bStr);
 pNode1->get_nextSibling(&pNode);
 RELEASE(pNode1);    // и новый указ - туда ж! :-)
 pNode->get_text(&bStr);
 lstrcpy(wdataPtr->stName, CW2A(bStr));        
 ::SysFreeString(bStr);                            
 pNode->get_nextSibling(&pNode1);
 RELEASE(pNode);        
 pNode1->get_text(&bStr);                                        
 lstrcpy(wdataPtr->stDesh, CW2A(bStr));  
 ::SysFreeString(bStr);
  RELEASE(pNode1);
 wdataPtr++;                                
}

Код работает железно, "утекуна" нет, даже при lvalue равном 10000! (Такой код на ASP-VBasic моментутельно "вывесил" бы сервер )))) )
P.S. vi2, а ты,сл`учаем, не "Московский бамбук"? )))
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.