Здравствуйте 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??
}
Ясно, а есть ли какое средство вроде 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;
}
Здравствуйте aLEXa123, Вы писали:
LEX>Ясно, а есть ли какое средство вроде CrtDumpMemoryLeaks() для определения утечек памяти в COM приложениях?
Я не знаю. Всё-таки это не "утечки" в обычной памяти задачи, которые можно "словить" в задаче. Есть такой интерфейс IMalloc и IMallocSpy, через которые реализованы SysAllocXXXX и т.д., но я ими не пользовался. Вроде как бы и незачем.
LEX>Как "поймать" leak`и от пропущенных комманд Release() ?
Никак. Это не лики. Это нормальное положение дел: клиент (какой-то) держит объект сервера. Может быть его уже и не существует, но для сервера картина не меняется.
Здравствуйте Vi2, Вы писали:
Vi2>Не знаю возможно ли такое в принципе. Дело касается памяти, выделенной по SysAllocString.
Судя по MSDN можно, так как SysAllocString внутри выделяется память через CoTaskMemAlloc (которя работате через IMalloc::Alloc), можно установить шпиона через CoRegisterMallocSpy (реализовав интерфейс IMallocSpy). Но надо учесть, что реализация строк кеширует память и поэтому отдает ее не сразу, так что определить утечку можно, но достаточно сложно.
Вот фрагмент с консоли при пропущенном 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!?
Vi2>Никак. Это не лики. Это нормальное положение дел: клиент (какой-то) держит объект сервера. Может быть его уже и не существует, но для сервера картина не меняется.
Здравствуйте 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!?
Вообщем, ситуация такова. Это не лики, это потеря объекта. А поскольку объект содержит некий объём памяти, и потеря памяти.
При неосвобождённом хотя бы одном своём объекте сервер не имеет право завершиться, поэтому ситуация ликов еще не наступила, поскольку задача не завершается.
Если же сервер решил завершиться, невзирая на существование своих объектов, то в потере памяти виноват сервер, а не пропущенный Release(). Это случается при падении сервера и при нормальных клиентах. Опять же это не лики как таковые — дай возможность объектам завершиться и ликов не будет.
Есть средства, наподобие тех, которые ты показал. При условии, что клииентов действительно нет, а ссылки есть. А это известно только тестеру. ИМХО, программно это не определить — есть ли клиент вот для этого объекта сервера.
Здравствуйте Vi2, Вы писали:
Vi2>Здравствуйте aLEXa123, Вы писали:
LEX>>Ясно, а есть ли какое средство вроде CrtDumpMemoryLeaks() для определения утечек памяти в COM приложениях?
Vi2>Я не знаю. Всё-таки это не "утечки" в обычной памяти задачи, которые можно "словить" в задаче. Есть такой интерфейс IMalloc и IMallocSpy, через которые реализованы SysAllocXXXX и т.д., но я ими не пользовался. Вроде как бы и незачем.
В RSDN Magazine #0 была статья Влада про ловлю ликов с помощью IMallocSpy.
LEX>>Как "поймать" leak`и от пропущенных комманд Release() ?
Vi2>Никак. Это не лики. Это нормальное положение дел: клиент (какой-то) держит объект сервера. Может быть его уже и не существует, но для сервера картина не меняется.
Ну, вообще говоря, это вопрос определения. Я как-то привык такие вещи тоже считать разновидностью ликов.
P.S. А вообще, юзайте Bounds Checker — он рулит. Большинство утечек ловит на раз. В том числе и с SysAllocString. Правда все-таки не все.
Здравствуйте 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], то нет (кроме последней итерации цикла — здесь она тоже будет).
Здравствуйте Lexey, Вы писали:
L>Я бы даже сказал безотносительно конкретного интерфейса. Если параметр [out], то утечка будет (при отсутствии ошибок). Если [in,out], то нет (кроме последней итерации цикла — здесь она тоже будет).
Меня смутила немного фраза из MSDN: The WebBrowser object ignores this property.
Если он игнорирует, значит, вполне может возвращать код ошибки или возвращать NULL. Тогда освобождать-то и нечего, и ликов не будет.
А по большому счёту согласен. Правило хорошего программирования, однако, — подчищай за собой, не оставляй подчистку на систему или на перезагрузку!
Здравствуйте 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;
Чиерт побьери, всегда приятно побеседовать с грамотным человеком !
С вышеознач. примером все ясно — память освобождается после команды 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`ов код отлично работает, только программа нагло жрет память
Здравствуйте 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 перед тем как в него запишешь другое значение. Например, переписав во временную переменную:
Vi2>Да потому что непутевый код, потому и работает! Это завсегда так.
ЭЭЭ-т точно! (Сказал товарищь Сухов! ) Vi2>Так или иначе, тебе нужно освобождать предыдущее значение pNode перед тем как в него запишешь другое значение. Например, переписав во временную переменную:
Именно эт я и сделал! Пришлось "ввести" этой проге в одно место новый указ.- Node1!
Код работает железно, "утекуна" нет, даже при lvalue равном 10000! (Такой код на ASP-VBasic моментутельно "вывесил" бы сервер )))) )
P.S. vi2, а ты,сл`учаем, не "Московский бамбук"? )))