Утечка памяти и потоки
От: Nik_Nik  
Дата: 04.06.04 08:36
Оценка:
Здравствуйте.

Может кто боролся с подобной проблемой.
Есть COM обект ObjTest с методом MethodTest и Connection Point Fire_EventTest.
В методе создается поток в котором выполняются некоторые действия и вызывается Event:

STDMETHODIMP CObjTest::MethodTest()
{
    // TODO: Add your implementation code here
    HANDLE hThread = 0;
    DWORD tid;
    if((hThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)Th_Test, (void *)this, 0, &tid)) == NULL)
    {
        return(E_FAIL);
    }
    CloseHandle(hThread);
    return S_OK;
}
void __cdecl Th_Test(void* Param)
{
    HRESULT hRes = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    ATLASSERT(SUCCEEDED(hRes));
    //некоторые действия
    CObjTest* pObjTest = (CObjTest*)Param;
    pObjTest->Fire_EventTest();

    ::CoUninitialize();
}

Класс для 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 утечек памяти не показывает.
Куда расходуется память? И как это можно победить?
Заранее благодарен.
Re: Утечка памяти и потоки
От: rus blood Россия  
Дата: 04.06.04 09:28
Оценка:
Здравствуйте, 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 память так и остается неосвобожденной?
Имею скафандр — готов путешествовать!
Re[2]: Утечка памяти и потоки
От: Nik_Nik  
Дата: 04.06.04 10:37
Оценка:
Здравствуйте, 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 память не освобождается.
Re[3]: Утечка памяти и потоки
От: rus blood Россия  
Дата: 04.06.04 10:53
Оценка:
RB>>1. А что, реализация IConnectionPointImplMT не требует маршаллинга? (это просто вопрос, в целях самообразования).
N_N>Cудя по примеру на сайте Microsoft не требует. Хотя может быть я чого-то не понимаю.

Вообще-то, если ты имеешь в виду этот пример, то там стоит multithreaded, а у тебя apartement...
Имею скафандр — готов путешествовать!
Re[4]: Утечка памяти и потоки
От: Nik_Nik  
Дата: 04.06.04 11:21
Оценка:
Здравствуйте, rus blood, Вы писали:


RB>>>1. А что, реализация IConnectionPointImplMT не требует маршаллинга? (это просто вопрос, в целях самообразования).

N_N>>Cудя по примеру на сайте Microsoft не требует. Хотя может быть я чого-то не понимаю.

RB>Вообще-то, если ты имеешь в виду этот пример, то там стоит multithreaded, а у тебя apartement...


Если поменять
CoInitializeEx(NULL, COINIT_MULTITHREADED)
эффект тотже самый.
Может что еще нужно поменять.

Как вообще корректно сделать такой COM объект? Может кинешь ссылку на исходники/статью.
Re[5]: Утечка памяти и потоки
От: rus blood Россия  
Дата: 04.06.04 11:31
Оценка:
N_N>Если поменять
N_N>
N_N>CoInitializeEx(NULL, COINIT_MULTITHREADED)
N_N>
эффект тотже самый.

N_N>Может что еще нужно поменять.

N_N>Как вообще корректно сделать такой COM объект? Может кинешь ссылку на исходники/статью.


Не понял, что значит "такой". Нормальный com-объект...

Вообще говоря, VB (если это не .net, конечно) не работает с free-threading.
Он работает только в apartment-ах. Лучше бы ты попробовал наоборот...
Имею скафандр — готов путешествовать!
Re[6]: Утечка памяти и потоки
От: Nik_Nik  
Дата: 04.06.04 11:47
Оценка:
Здравствуйте, rus blood, Вы писали:


N_N>>Если поменять

N_N>>
N_N>>CoInitializeEx(NULL, COINIT_MULTITHREADED)
N_N>>
эффект тотже самый.

N_N>>Может что еще нужно поменять.

N_N>>Как вообще корректно сделать такой COM объект? Может кинешь ссылку на исходники/статью.


RB>Не понял, что значит "такой". Нормальный com-объект...


Те ты хочешь сказать, что СОМ объект сделан нормально, вся проблема в VB?

RB>Вообще говоря, VB (если это не .net, конечно) не работает с free-threading.


Я про это читал, поэтому и сделал COINIT_APARTMENTTHREADED .

RB>Он работает только в apartment-ах. Лучше бы ты попробовал наоборот...


Что значит наоборот? Сделать клиента на VC++.
В том-то и дело, что этот СОМ объект должен использоваться именно в программе на VB.
Те, для кого он делается, кроме VB не на чем не пишут .
Re: Утечка памяти и потоки
От: Tom Россия http://www.RSDN.ru
Дата: 04.06.04 12:18
Оценка:
N_N>Bounds Checker утечек памяти не показывает.
N_N>Куда расходуется память? И как это можно победить?
N_N>Заранее благодарен.

1. task manager ещё ничего не определяет
2. что то мне говорит, что WINAPI — это __stdcall а не _cdecl
3. поток создавай при помощи beginthread
Народная мудрось
всем все никому ничего(с).
Re[2]: Утечка памяти и потоки
От: Nik_Nik  
Дата: 04.06.04 13:02
Оценка:
Здравствуйте, 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.

Неужели никто не делал что-то подобное?
Re[3]: Утечка памяти и потоки
От: rus blood Россия  
Дата: 04.06.04 13:30
Оценка:
N_N>А кто говорил про WINAPI?
N_N>Вообще __cdecl остался со времен использования _beginthread, которому нужен указатель на
N_N>void( __cdecl *start_address )( void * ), но при этом были какието глюки.
N_N>Я про это уже писал. То же было и при _beginthreadex.

N_N>Неужели никто не делал что-то подобное?


Я сделал. Только что
Ровно, как у тебя.

Память растет.
Имею скафандр — готов путешествовать!
Re[4]: Утечка памяти и потоки
От: Nik_Nik  
Дата: 04.06.04 13:42
Оценка:
Здравствуйте, rus blood, Вы писали:


N_N>>А кто говорил про WINAPI?

N_N>>Вообще __cdecl остался со времен использования _beginthread, которому нужен указатель на
N_N>>void( __cdecl *start_address )( void * ), но при этом были какието глюки.
N_N>>Я про это уже писал. То же было и при _beginthreadex.

N_N>>Неужели никто не делал что-то подобное?


RB>Я сделал. Только что

RB>Ровно, как у тебя.

RB>Память растет.


Ну если также, как у меня, то почему бы ей не расти.
Я с этой фигней уже неделю парюсь. Сначала думал это из за передачи SAFEARRAY. Но оказалось, что нет.
Вообще я надеялся что может я чегото не понимаю, и нужно что-то делать по другому.
Re[5]: Утечка памяти и потоки
От: rus blood Россия  
Дата: 04.06.04 14:35
Оценка:
N_N>Ну если также, как у меня, то почему бы ей не расти.
N_N>Я с этой фигней уже неделю парюсь. Сначала думал это из за передачи SAFEARRAY. Но оказалось, что нет.
N_N>Вообще я надеялся что может я чегото не понимаю, и нужно что-то делать по другому.

Растет, если делать старт потоков. А долго ты мерил память?

У меня было так.
— сначала память растет
— потом растет, но скачками, т.е. периодически обваливается.
— отожравши 30 метров в оперативке и 20 в виртуалке почему-то рост прекратился. Т.е. performance counter на private bytes показывал горизонтальную линию, но прога работала — CPU был такой же (60-80%).
— потом я это безобразие остановил и дал отдохнуть.
— через какое-то время память в оперативке обвалилась до 10 метров.
— после повторного запуска память крутилась вокруг отметки 10, и не росла...

Может, не так страшен черт???
Имею скафандр — готов путешествовать!
Re: Утечка памяти и потоки
От: Andrusha  
Дата: 04.06.04 14:41
Оценка:
Здравствуйте, 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).

CObjTest — STA или MTA?
Re[6]: Утечка памяти и потоки
От: Nik_Nik  
Дата: 04.06.04 15:14
Оценка:
Здравствуйте, rus blood, Вы писали:


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>Может, не так страшен черт???


Может быть, но это компонент для коииуникации который собираются использовать в программе для производства. И если программа скажет, что нет памяти, а рядом не будет оператора, то это не будет хорошо.
Re[2]: Утечка памяти и потоки
От: Nik_Nik  
Дата: 04.06.04 15:21
Оценка:
Здравствуйте, 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 — результат одинаковый.
Re[3]: Утечка памяти и потоки
От: rus blood Россия  
Дата: 04.06.04 15:52
Оценка:
A>>::WaitForSingleObject(hThread, INFINITE); // Дожидаемся завершения потока, прежде чем его прибитьN_N>
N_N>Так не пробовал (но обязательно попробую), но это сильно уменьшит производительность системы. Время ответа большое.

1. Насчет производительности. Т.к. VB не поддерживает multithreading, то объект создан в STA, и все вызовы в него сериализуются. В честности, вызов метода MethodTest всегда происходит в одном и том же потоке, а не в разных, как можно было бы подумать.

2. Дожидаться окончания потока, конечно, не надо. Иначе получишь deadlock (из-за особенности п.1, если бы был MTA, получишь stack overflow).
Имею скафандр — готов путешествовать!
Re[4]: Утечка памяти и потоки
От: Nik_Nik  
Дата: 07.06.04 07:20
Оценка:
Здравствуйте, 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?
Re[4]: Утечка памяти и потоки
От: Andrusha  
Дата: 07.06.04 07:31
Оценка:
Здравствуйте, rus blood, Вы писали:


RB>1. Насчет производительности. Т.к. VB не поддерживает multithreading, то объект создан в STA, и все вызовы в него сериализуются. В честности, вызов метода MethodTest всегда происходит в одном и том же потоке, а не в разных, как можно было бы подумать.


RB>2. Дожидаться окончания потока, конечно, не надо. Иначе получишь deadlock (из-за особенности п.1, если бы был MTA, получишь stack overflow).

Ты заблуждаешься. Никаких deadlock'ов не будет.
Re[5]: Утечка памяти и потоки
От: rus blood Россия  
Дата: 07.06.04 09:14
Оценка:
RB>>1. Насчет производительности. Т.к. VB не поддерживает multithreading, то объект создан в STA, и все вызовы в него сериализуются. В честности, вызов метода MethodTest всегда происходит в одном и том же потоке, а не в разных, как можно было бы подумать.

A>Ты заблуждаешься. Никаких deadlock'ов не будет.


Да, точно. Если поставить COINIT_MULTITHREADED, CComMultiThreadModel, _ATL_FREE_THREADED и val ThreadingModel = s 'Free', то MethodTest вызывается из разных потоков... Тогда deadlock-ов может и не будет...
В, общем,
Имею скафандр — готов путешествовать!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.