Mam wielowątkową usługę Win32 napisaną w C++ (VS2010), która szeroko wykorzystuje standardową bibliotekę szablonów. Logika biznesowa programu działa poprawnie, ale patrząc na menedżera zadań (lub menedżera zasobów) program wyciekuje pamięć jak sito.Problemy z pamięcią w wielowątkowej usłudze Win32 używającej STL na VS2010
Mam zestaw testowy, który zawiera około 16 równoczesnych żądań/sekundę. Po pierwszym uruchomieniu program zużywa się gdzieś w okolicy 1,5 MB pamięci RAM. Po pełnym teście (trwającym 12-15 minut) zużycie pamięci kończy się w okolicach 12 Mb. Zwykle nie stanowiłoby to problemu dla programu, który uruchamia się raz, a następnie kończy, ale program ten ma działać nieprzerwanie. Bardzo źle.
Aby spróbować zawęzić problem, utworzyłem bardzo małą aplikację testową, która obraca wątki robocze z szybkością co 250 ms. Wątek roboczy tworzy mapę i zapełnia ją pseudolosowymi danymi, opróżnia mapę, a następnie kończy działanie. Ten program również przecieka pamięć w podobny sposób, więc myślę, że problem polega na tym, że STL nie zwalnia pamięci zgodnie z oczekiwaniami.
Próbowałem VLD, aby wyszukać nieszczelności i znalazłem parę, którą naprawiłem, ale nadal pozostaje problem. Próbowałem zintegrować Hoarda, ale to faktycznie pogorszyło problem (prawdopodobnie nie integruję go poprawnie, ale nie widzę jak).
Chciałbym postawić następujące pytanie: czy możliwe jest stworzenie programu wykorzystującego STL w środowisku wielowątkowym, które nie spowoduje wycieku pamięci? W ciągu ostatniego tygodnia dokonałem co najmniej 200 zmian w tym programie. Przedstawiłem wyniki zmian i wszystkie mają ten sam podstawowy profil. Nie chcę, aby usunąć całą dobroć STL, która znacznie ułatwiła rozwój tej aplikacji. Gorąco doceniam wszelkie sugestie na temat tego, jak mogę sprawić, by ta aplikacja działała bez przecieków pamięci, tak jak wychodzi z mody.
Jeszcze raz dziękuję za pomoc!
P.S. Publikuję kopię testu pamięci do inspekcji/osobistego montażu.
#include <string>
#include <iostream>
#include <Windows.h>
#include <map>
using namespace std;
#define MAX_THD_COUNT 1000
DWORD WINAPI ClientThread(LPVOID param)
{
unsigned int thdCount = (unsigned int)param;
map<int, string> m;
for (unsigned int x = 0; x < 1000; ++x)
{
string s;
for (unsigned int y = 0; y < (x % (thdCount + 1)); ++y)
{
string z = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
unsigned int zs = z.size();
s += z[(y % zs)];
}
m[x] = s;
}
m.erase(m.begin(), m.end());
ExitThread(0);
return 0;
}
int main(int argc, char ** argv)
{
// wait for start
string inputWait;
cout << "type g and press enter to go: ";
cin >> inputWait;
// spawn many memory-consuming threads
for (unsigned int thdCount = 0; thdCount < MAX_THD_COUNT; ++thdCount)
{
CreateThread(NULL, 0, ClientThread, (LPVOID)thdCount, NULL, NULL);
cout
<< (int)(MAX_THD_COUNT - thdCount)
<< endl;
Sleep(250);
}
// wait for end
cout << "type e and press enter to end: ";
cin >> inputWait;
return 0;
}
'm.erase (m.begin(), m.end())' będzie "m.clear()' w większości książek, ale ponieważ wygasa po powrocie proc mimo to, nie jestem pewien dlaczego jest nawet tam. Poza tym może wystąpić fragmentacja i/lub nieczyste zamknięcie CRT. W tym celu powinieneś używać '_beginthreadex()' dla swoich wątków, i * nie * 'ExitThread()' w drodze na zewnątrz. niech wątek proc wygaśnie przez-return. Co więcej, przeciekasz uchwyt wątku przy każdym wykonaniu. Powinien zostać zamknięty zaraz po 'CreateThread()', który aktualnie nie zapisuje nawet uchwytu. – WhozCraig
Zapomniałem usunąć ExitThread() z postu. Próbowałem tego raz i nie zrobił nic, aby pomóc, więc szybko go usunąłem. Masz rację co do jasności, a ja użyłem obu wersji na wypadek, gdyby było coś ukrytego, czego mi brakowało. Przyjrzę się użyciu '_beginthreadex()', aby sprawdzić, czy to pomaga. Całkowicie przegapiłem zamknięcie uchwytu nici. Dzięki! –
Zobacz tutaj http://support.microsoft.com/kb/104641/en-gb to może być nic. – James