Может кто боролся с подобной проблемой.
Есть COM обект ObjTest с методом MethodTest и Connection Point Fire_EventTest.
В методе создается поток в котором выполняются некоторые действия и вызывается Event:
Класс для Connection Point порожден от IConnectionPointImplMT (ATLCPImplMT.h).
Клиент на VB
Dim WithEvents ObjT As ObjTest
Dim MultExecute As Boolean
Private Sub Command1_Click()
MultExecute = True
ObjT.MethodTest
End Sub
Private Sub Command3_Click()
MultExecute = False
End Sub
Private Sub ObjT_EventTest()
If (MultExecute ) Then
ObjT.MethodTest
End If
End Sub
После нажатия на кнопку (Command1_Click) Task Manager показывает нарастание памяти процесса.
Bounds Checker утечек памяти не показывает.
Куда расходуется память? И как это можно победить?
Заранее благодарен.
Здравствуйте, Nik_Nik, Вы писали:
N_N>Здравствуйте.
N_N>Может кто боролся с подобной проблемой. N_N>Есть COM обект ObjTest с методом MethodTest и Connection Point Fire_EventTest. N_N>В методе создается поток в котором выполняются некоторые действия и вызывается Event:
N_N>
.............
N_N>
N_N>Класс для Connection Point порожден от IConnectionPointImplMT (ATLCPImplMT.h).
N_N>Клиент на VB N_N>
..........
N_N>
N_N>После нажатия на кнопку (Command1_Click) Task Manager показывает нарастание памяти процесса. N_N>Bounds Checker утечек памяти не показывает. N_N>Куда расходуется память? И как это можно победить? N_N>Заранее благодарен.
1. А что, реализация IConnectionPointImplMT не требует маршаллинга? (это просто вопрос, в целях самообразования).
2. Есть различия между _beginthreadex и CreateThread, которые в некоторых случаях могут давать утечки. См. MSDN, а также код Fire_EventTest.
3. Я так понимаю, что после нажатия на кнопку 1, начинают бесконечно порождаться потоки, один за одним. Может сисмета просто не успевает освобождать память под них. После нажатия на кнопку 3 память так и остается неосвобожденной?
Здравствуйте, rus blood, Вы писали:
RB>Здравствуйте, Nik_Nik, Вы писали:
... RB>1. А что, реализация IConnectionPointImplMT не требует маршаллинга? (это просто вопрос, в целях самообразования).
Cудя по примеру на сайте Microsoft не требует. Хотя может быть я чого-то не понимаю.
RB>2. Есть различия между _beginthreadex и CreateThread, которые в некоторых случаях могут давать утечки. См. MSDN, а также код Fire_EventTest.
А более точную ссылку в MSDN можешь дать?
Вообще изначально я пользовался _beginthreadex, но было тоже самое + иногда происходили непонятные глюки при передаче SAFEARRAY через Connection Point (в тестовом примере я это убрал).
RB>3. Я так понимаю, что после нажатия на кнопку 1, начинают бесконечно порождаться потоки, один за одним. Может сисмета просто не успевает освобождать память под них. После нажатия на кнопку 3 память так и остается неосвобожденной?
Да потоки порождаются, но и уничтожаются (смотрел в отладчике VC и в Bounds Checker). Более 6 потоков одновременно не существует, причем 3 из них создаются сами и существуют до завершения программы. После нажатия на кнопку 3 память не освобождается.
RB>>1. А что, реализация IConnectionPointImplMT не требует маршаллинга? (это просто вопрос, в целях самообразования). N_N>Cудя по примеру на сайте Microsoft не требует. Хотя может быть я чого-то не понимаю.
Вообще-то, если ты имеешь в виду этот пример, то там стоит multithreaded, а у тебя apartement...
RB>>>1. А что, реализация IConnectionPointImplMT не требует маршаллинга? (это просто вопрос, в целях самообразования). N_N>>Cудя по примеру на сайте Microsoft не требует. Хотя может быть я чого-то не понимаю.
RB>Вообще-то, если ты имеешь в виду этот пример, то там стоит multithreaded, а у тебя apartement...
Если поменять
CoInitializeEx(NULL, COINIT_MULTITHREADED)
эффект тотже самый.
Может что еще нужно поменять.
Как вообще корректно сделать такой COM объект? Может кинешь ссылку на исходники/статью.
эффект тотже самый. N_N>>Может что еще нужно поменять.
N_N>>Как вообще корректно сделать такой COM объект? Может кинешь ссылку на исходники/статью.
RB>Не понял, что значит "такой". Нормальный com-объект...
Те ты хочешь сказать, что СОМ объект сделан нормально, вся проблема в VB?
RB>Вообще говоря, VB (если это не .net, конечно) не работает с free-threading.
Я про это читал, поэтому и сделал COINIT_APARTMENTTHREADED .
RB>Он работает только в apartment-ах. Лучше бы ты попробовал наоборот...
Что значит наоборот? Сделать клиента на VC++.
В том-то и дело, что этот СОМ объект должен использоваться именно в программе на VB.
Те, для кого он делается, кроме VB не на чем не пишут .
Здравствуйте, Tom, Вы писали:
N_N>>Bounds Checker утечек памяти не показывает. N_N>>Куда расходуется память? И как это можно победить? N_N>>Заранее благодарен.
Tom>1. task manager ещё ничего не определяет
А если, когда запустить на несколько суток, увеличивается своп, это что-то определяет?
Tom>2. что то мне говорит, что WINAPI — это __stdcall а не _cdecl Tom>3. поток создавай при помощи beginthread
А кто говорил про WINAPI?
Вообще __cdecl остался со времен использования _beginthread, которому нужен указатель на
void( __cdecl *start_address )( void * ), но при этом были какието глюки.
Я про это уже писал. То же было и при _beginthreadex.
N_N>А кто говорил про WINAPI? N_N>Вообще __cdecl остался со времен использования _beginthread, которому нужен указатель на N_N>void( __cdecl *start_address )( void * ), но при этом были какието глюки. N_N>Я про это уже писал. То же было и при _beginthreadex.
N_N>Неужели никто не делал что-то подобное?
N_N>>А кто говорил про WINAPI? N_N>>Вообще __cdecl остался со времен использования _beginthread, которому нужен указатель на N_N>>void( __cdecl *start_address )( void * ), но при этом были какието глюки. N_N>>Я про это уже писал. То же было и при _beginthreadex.
N_N>>Неужели никто не делал что-то подобное?
RB>Я сделал. Только что RB>Ровно, как у тебя.
RB>Память растет.
Ну если также, как у меня, то почему бы ей не расти.
Я с этой фигней уже неделю парюсь. Сначала думал это из за передачи SAFEARRAY. Но оказалось, что нет.
Вообще я надеялся что может я чегото не понимаю, и нужно что-то делать по другому.
N_N>Ну если также, как у меня, то почему бы ей не расти. N_N>Я с этой фигней уже неделю парюсь. Сначала думал это из за передачи SAFEARRAY. Но оказалось, что нет. N_N>Вообще я надеялся что может я чегото не понимаю, и нужно что-то делать по другому.
Растет, если делать старт потоков. А долго ты мерил память?
У меня было так.
— сначала память растет
— потом растет, но скачками, т.е. периодически обваливается.
— отожравши 30 метров в оперативке и 20 в виртуалке почему-то рост прекратился. Т.е. performance counter на private bytes показывал горизонтальную линию, но прога работала — CPU был такой же (60-80%).
— потом я это безобразие остановил и дал отдохнуть.
— через какое-то время память в оперативке обвалилась до 10 метров.
— после повторного запуска память крутилась вокруг отметки 10, и не росла...
Здравствуйте, Nik_Nik, Вы писали:
N_N>Здравствуйте.
N_N>Может кто боролся с подобной проблемой. N_N>Есть COM обект ObjTest с методом MethodTest и Connection Point Fire_EventTest. N_N>В методе создается поток в котором выполняются некоторые действия и вызывается Event:
N_N>
N_N>STDMETHODIMP CObjTest::MethodTest()
N_N>{
N_N> // TODO: Add your implementation code here
N_N> HANDLE hThread = 0;
N_N> DWORD tid;
N_N> if((hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Th_Test, (void *)this, 0, &tid)) == NULL)
N_N> {
N_N> return(E_FAIL);
N_N> }
::WaitForSingleObject(hThread, INFINITE); // Дожидаемся завершения потока, прежде чем его прибитьN_N> CloseHandle(hThread);
N_N> return S_OK;
N_N>}
N_N>void __cdecl Th_Test(void* Param)
N_N>{
N_N> HRESULT hRes = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
N_N> ATLASSERT(SUCCEEDED(hRes));
N_N> //некоторые действия
N_N> CObjTest* pObjTest = (CObjTest*)Param;
N_N> pObjTest->Fire_EventTest();
N_N> ::CoUninitialize();
N_N>}
N_N> N_N>Класс для Connection Point порожден от IConnectionPointImplMT (ATLCPImplMT.h).
N_N>>Ну если также, как у меня, то почему бы ей не расти. N_N>>Я с этой фигней уже неделю парюсь. Сначала думал это из за передачи SAFEARRAY. Но оказалось, что нет. N_N>>Вообще я надеялся что может я чегото не понимаю, и нужно что-то делать по другому.
RB>Растет, если делать старт потоков. А долго ты мерил память?
Что значит делать старт потоков? Если создавать потоки, то это так и должно быть (такова логика).
Я гонял двое суток. Причем создавал условия чтобы физической памяьти оставалось мало. Своп растет.
RB>У меня было так. RB>- сначала память растет RB>- потом растет, но скачками, т.е. периодически обваливается. RB>- отожравши 30 метров в оперативке и 20 в виртуалке почему-то рост прекратился. Т.е. performance counter на private bytes показывал горизонтальную линию, но прога работала — CPU был такой же (60-80%). RB>- потом я это безобразие остановил и дал отдохнуть.
А что значит отдохнуть? Я останавливал минуты на 3. При остановке это значение падает, в течении 10 сек (Win2K), но не значительно (не до значения при предыдущей остановке), а ~16К, а при повторном запуске продолжает рости. RB>- через какое-то время память в оперативке обвалилась до 10 метров.
Я тоже наблюдал иногда резкие уменьшения в меньшую сторону, но общее напрвавление сохранялось. RB>- после повторного запуска память крутилась вокруг отметки 10, и не росла...
Такого не было.
Я в основном тестировал свой COM объект. То, что в примере это сильно урезаный вариант. Но прибавки в памяти примерно того же порядка. Самое интересное что Bound Checker прироста памяти не показывает. Может я что не так его настроил. Если ты пользовался им для тестирования COM? То расказжи как правильно настроить.
RB>Может, не так страшен черт???
Может быть, но это компонент для коииуникации который собираются использовать в программе для производства. И если программа скажет, что нет памяти, а рядом не будет оператора, то это не будет хорошо.
Здравствуйте, Andrusha, Вы писали:
A>Здравствуйте, Nik_Nik, Вы писали:
N_N>>Здравствуйте.
N_N>>Может кто боролся с подобной проблемой. N_N>>Есть COM обект ObjTest с методом MethodTest и Connection Point Fire_EventTest. N_N>>В методе создается поток в котором выполняются некоторые действия и вызывается Event:
N_N>>
N_N>>STDMETHODIMP CObjTest::MethodTest()
N_N>>{
N_N>> // TODO: Add your implementation code here
N_N>> HANDLE hThread = 0;
N_N>> DWORD tid;
N_N>> if((hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Th_Test, (void *)this, 0, &tid)) == NULL)
N_N>> {
N_N>> return(E_FAIL);
N_N>> }
A>::WaitForSingleObject(hThread, INFINITE); // Дожидаемся завершения потока, прежде чем его прибитьN_N>
Так не пробовал (но обязательно попробую), но это сильно уменьшит производительность системы. Время ответа большое.
CloseHandle(hThread);
N_N>> return S_OK;
N_N>>}
N_N>>void __cdecl Th_Test(void* Param)
N_N>>{
N_N>> HRESULT hRes = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
N_N>> ATLASSERT(SUCCEEDED(hRes));
N_N>> //некоторые действия
N_N>> CObjTest* pObjTest = (CObjTest*)Param;
N_N>> pObjTest->Fire_EventTest();
N_N>> ::CoUninitialize();
N_N>>}
N_N>> N_N>>Класс для Connection Point порожден от IConnectionPointImplMT (ATLCPImplMT.h).
A>CObjTest — STA или MTA?
Я пробовал и COINIT_APARTMENTTHREADED и COINIT_MULTITHREADED — результат одинаковый.
A>>::WaitForSingleObject(hThread, INFINITE); // Дожидаемся завершения потока, прежде чем его прибитьN_N> N_N>Так не пробовал (но обязательно попробую), но это сильно уменьшит производительность системы. Время ответа большое.
1. Насчет производительности. Т.к. VB не поддерживает multithreading, то объект создан в STA, и все вызовы в него сериализуются. В честности, вызов метода MethodTest всегда происходит в одном и том же потоке, а не в разных, как можно было бы подумать.
2. Дожидаться окончания потока, конечно, не надо. Иначе получишь deadlock (из-за особенности п.1, если бы был MTA, получишь stack overflow).
Здравствуйте, rus blood, Вы писали:
A>>>::WaitForSingleObject(hThread, INFINITE); // Дожидаемся завершения потока, прежде чем его прибитьN_N> N_N>>Так не пробовал (но обязательно попробую), но это сильно уменьшит производительность системы. Время ответа большое.
RB>1. Насчет производительности. Т.к. VB не поддерживает multithreading, то объект создан в STA, и все вызовы в него сериализуются. В честности, вызов метода MethodTest всегда происходит в одном и том же потоке, а не в разных, как можно было бы подумать.
RB>2. Дожидаться окончания потока, конечно, не надо. Иначе получишь deadlock (из-за особенности п.1, если бы был MTA, получишь stack overflow).
Большое спасибо за ответы.
В том примере который я привел, действительно после ~0.5часа работы память увеличиваться перестает. Видимо у меня проблемы связаны с чем-то другим, скорее всего с передачей данных.
Возвращаясь к написанному ранее:
Как будет корректнее вызывать CoInitializeEx с COINIT_APARTMENTTHREADED или COINIT_MULTITHREADED учитывая что клиент на VB. Насколько я понял программа на VB выполняется в одном потоке, даже если Event-ы приходят из других потоков.
Где можно подробнее почитать, как это работает и как передаются данные через Connection Point?
RB>1. Насчет производительности. Т.к. VB не поддерживает multithreading, то объект создан в STA, и все вызовы в него сериализуются. В честности, вызов метода MethodTest всегда происходит в одном и том же потоке, а не в разных, как можно было бы подумать.
RB>2. Дожидаться окончания потока, конечно, не надо. Иначе получишь deadlock (из-за особенности п.1, если бы был MTA, получишь stack overflow).
Ты заблуждаешься. Никаких deadlock'ов не будет.
RB>>1. Насчет производительности. Т.к. VB не поддерживает multithreading, то объект создан в STA, и все вызовы в него сериализуются. В честности, вызов метода MethodTest всегда происходит в одном и том же потоке, а не в разных, как можно было бы подумать.
A>Ты заблуждаешься. Никаких deadlock'ов не будет.
Да, точно. Если поставить COINIT_MULTITHREADED, CComMultiThreadModel, _ATL_FREE_THREADED и val ThreadingModel = s 'Free', то MethodTest вызывается из разных потоков... Тогда deadlock-ов может и не будет...
В, общем,