Czy istnieje przeciek pamięci?
class myclass : public boost::enable_shared_from_this<myclass>{
//...
void broadcast(const char *buf){
broadcast(new std::string(buf));
}
void broadcast(std::string *buf){
boost::shared_ptr<std::string> msg(buf);
}
//...
};
(To jest uproszczona wersja, w której nadal występuje problem - normalnie wykonuję prawdziwą pracę w tym drugim wywołaniu broadcast
!) Założyłem, że pierwsze połączenie dostaje trochę pamięci, a ponieważ nic nie robię z inteligentnym wskaźnikiem, drugie połączenie natychmiast je usunie. Prosty? Ale kiedy uruchamiam mój program, pamięć rośnie z czasem, skokowo. Jednak kiedy komentuję jedyne wywołanie w programie do broadcast(), tak nie jest!
Wyjście ps dla wersji bez broadcast()
:
%CPU %MEM VSZ RSS TIME
3.2 0.0 158068 1988 0:00
3.3 0.0 158068 1988 0:25 (12 mins later)
Z wywołaniem broadcast()
(na Ubuntu 10.04, g++ 4.4, boost 1.40)
%CPU %MEM VSZ RSS TIME
1.0 0.0 158068 1980 0:00
3.3 0.0 158068 1988 0:04 (2 mins)
3.4 0.0 223604 1996 0:06 (3.5 mins)
3.3 0.0 223604 2000 0:09
3.1 0.0 223604 2000 2:21 (82 mins)
3.1 0.0 223604 2000 3:50 (120 mins)
(Widzenie tego skoku po około 3 minutach jest powtarzalne w kilku próbach, które do tej pory próbowałem).
Z wezwaniem do broadcast()
(na Centos 5.6, g++ 4.1, boost 1.41)
%CPU %MEM VSZ RSS TIME
0.0 0.0 51224 1744 0:00
0.0 0.0 51224 1744 0:00 (30s)
1.1 0.0 182296 1776 0:02 (3.5 mins)
0.7 0.0 182296 1776 0:03
0.7 0.0 182296 1776 0:09 (20 mins)
0.7 0.0 247832 1788 0:14 (34 mins)
0.7 0.0 247832 1788 0:17
0.7 0.0 247832 1788 0:24 (55 mins)
0.7 0.0 247832 1788 0:36 (71 mins)
Oto jak wywoływany jest broadcast()
(z boost::asio timer) i teraz zastanawiam się, czy to może mieć znaczenie:
void callback(){
//...
timer.expires_from_now(boost::posix_time::milliseconds(20));
//...
char buf[512];
sprintf(buf,"...");
broadcast(buf);
timer.async_wait(boost::bind(&myclass::callback, shared_from_this() ));
//...
}
(callback jest w tej samej klasie co funkcja broadcast)
Mam 4 z tych liczników, a mój io_service.run()
jest wywoływany przez pulę 3 wątków. Mój limit czasu 20 ms oznacza, że każdy timer wywołuje broadcast()
50 razy na sekundę. Ustawiam wygaśnięcie na początku mojej funkcji i uruchamiam timer pod koniec. Wyeliminowany kod nie robi tak wiele; wysyłanie informacji debugowania do std::cout jest prawdopodobnie zadaniem najbardziej obciążającym procesor. Przypuszczam, że czasami może się zdarzyć, że timer uruchamia się natychmiast; ale nadal nie widzę, jaki byłby to problem, nie mówiąc już o spowodowaniu wycieku pamięci.
(Nawiasem mówiąc, program działa dobrze, nawet podczas wykonywania pełnych zadań; nabrałem podejrzeń tylko wtedy, gdy zauważyłem, że zużycie pamięci zgłoszone przez ps wzrosło.)
AKTUALIZACJA: Dziękujemy za odpowiedzi i komentarze. Dodam, że pozostawiłem program działający na każdym systemie na kolejne kilka godzin i zużycie pamięci już nie wzrosło. (Byłem też gotów odrzucić to jako jednorazową restrukturyzację stosu lub coś w tym rodzaju, kiedy wersja Centos skoczyła po raz drugi.) W każdym razie dobrze jest wiedzieć, że moje rozumienie inteligentnych wskaźników nadal jest dobre i że jest nie ma dziwnego przypadku narożnego z gwintowaniem, o który muszę się martwić.
2 odpowiedzi
W przypadku wycieku przydzielasz std::string
(20 bajtów, mniej więcej) 50 razy na sekundę. w ciągu 1 godziny powinieneś zostać przydzielony... 3600*50*20 = 3,4MBytes.
Widzisz, nie ma nic wspólnego z 64K, prawdopodobnie jest to spowodowane sposobem, w jaki system przydziela pamięć procesowi, który new
przydziela podrzędnie do zmiennych.
System, gdy coś jest usuwane, musi to „zbierać śmieci”, umieszczając je z powrotem w dostępnym łańcuchu pamięci w celu dalszych alokacji. Ale ponieważ zajmuje to trochę czasu, większość systemów nie wykonuje tej operacji, dopóki uwolniona pamięć nie przekroczy pewnych ilości, aby można było dokonać „przepakowania”.
Cóż, to, co się tutaj dzieje, prawdopodobnie nie polega na tym, że twój program przecieka, ale że z jakiegoś powodu alokator pamięci systemowej postanowił zachować kolejną stronę 64 kB dla twojej aplikacji. Gdyby w tym momencie wystąpił stały wyciek pamięci, z częstotliwością 50 Hz, miałoby to znacznie bardziej dramatyczny efekt!
Nie wiem dokładnie, dlaczego tak się dzieje po 3 minutach (nie jestem ekspertem w tej dziedzinie), ale domyślam się, że w grę wchodzą pewne heurystyki i statystyki. Albo może po prostu być pofragmentowana sterta.
Inną rzeczą, która mogła się zdarzyć, jest to, że wiadomości, które trzymasz w buforze, z czasem stają się dłuższe :)
Podobne pytania
Nowe pytania
c++
C ++ to język programowania ogólnego przeznaczenia. Pierwotnie został zaprojektowany jako rozszerzenie C i ma podobną składnię, ale teraz jest to zupełnie inny język. Użyj tego tagu w przypadku pytań dotyczących kodu (który ma zostać) skompilowany za pomocą kompilatora C ++. Użyj znacznika specyficznego dla wersji w przypadku pytań związanych z określoną wersją standardu [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] lub [C ++ 23] itp. .