W końcu udało mi się rozwiązać problem i chętnie podzielę się moimi odkryciami. Ogólnie najlepszym narzędziem do oceny wykorzystania pamięci przez program z mojej perspektywy jest narzędzie z Valgrind. pozwala na profilowanie zużycia sterty i daje szczegółową analizę.
Aby teraz odtworzyć stertę aplikacji pod numerem valgrind --tool=massif prog
, uzyskasz podstawowy dostęp do wszystkich informacji o typowych funkcjach przydzielania pamięci, takich jak malloc
i znajomych. Jednakże, aby kopać głębiej, aktywowałem opcję --pages-as-heap=yes
, która następnie będzie raportować nawet informacje o wywoływanych wywołaniach systemu. Aby dany przykład tutaj jest coś z mojej sesji profilowania:
67 1,284,382,720 978,575,360 978,575,360 0 0
100.00% (978,575,360B) (page allocation syscalls) mmap/mremap/brk, --alloc-fns, etc.
->87.28% (854,118,400B) 0x8282419: mmap (syscall-template.S:82)
| ->84.80% (829,849,600B) 0x821DF7D: _int_malloc (malloc.c:3226)
| | ->84.36% (825,507,840B) 0x821E49F: _int_memalign (malloc.c:5492)
| | | ->84.36% (825,507,840B) 0x8220591: memalign (malloc.c:3880)
| | | ->84.36% (825,507,840B) 0x82217A7: posix_memalign (malloc.c:6315)
| | | ->83.37% (815,792,128B) 0x4C74F9B: std::_Rb_tree_node<std::pair<std::string const, unsigned int> >* std::_Rb_tree<std::string, std::pair<std::string const, unsigned int>, std::_Select1st<std::pair<std::string const, unsigned int> >, std::less<std::string>, StrategizedAllocator<std::pair<std::string const, unsigned int>, MemalignStrategy<4096> > >::_M_create_node<std::pair<std::string, unsigned int> >(std::pair<std::string, unsigned int>&&) (MemalignStrategy.h:13)
| | | | ->83.37% (815,792,128B) 0x4C7529F: OrderIndifferentDictionary<std::string, MemalignStrategy<4096>, StrategizedAllocator>::addValue(std::string) (stl_tree.h:961)
| | | | ->83.37% (815,792,128B) 0x5458DC9: var_to_string(char***, unsigned long, unsigned long, AbstractTable*) (AbstractTable.h:341)
| | | | ->83.37% (815,792,128B) 0x545A466: MySQLInput::load(std::shared_ptr<AbstractTable>, std::vector<std::vector<ColumnMetadata*, std::allocator<ColumnMetadata*> >*, std::allocator<std::vector<ColumnMetadata*, std::allocator<ColumnMetadata*> >*> > const*, Loader::params const&) (MySQLLoader.cpp:161)
| | | | ->83.37% (815,792,128B) 0x54628F2: Loader::load(Loader::params const&) (Loader.cpp:133)
| | | | ->83.37% (815,792,128B) 0x4F6B487: MySQLTableLoad::executePlanOperation() (MySQLTableLoad.cpp:60)
| | | | ->83.37% (815,792,128B) 0x4F8F8F1: _PlanOperation::execute_throws() (PlanOperation.cpp:221)
| | | | ->83.37% (815,792,128B) 0x4F92B08: _PlanOperation::execute() (PlanOperation.cpp:262)
| | | | ->83.37% (815,792,128B) 0x4F92F00: _PlanOperation::operator()() (PlanOperation.cpp:204)
| | | | ->83.37% (815,792,128B) 0x656F9B0: TaskQueue::executeTask() (TaskQueue.cpp:88)
| | | | ->83.37% (815,792,128B) 0x7A70AD6: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16)
| | | | ->83.37% (815,792,128B) 0x6BAEEFA: start_thread (pthread_create.c:304)
| | | | ->83.37% (815,792,128B) 0x8285F4B: clone (clone.S:112)
| | | |
| | | ->00.99% (9,715,712B) in 1+ places, all below ms_print's threshold (01.00%)
| | |
| | ->00.44% (4,341,760B) in 1+ places, all below ms_print's threshold (01.00%)
Jak widać ~ 85% mojego alokacji pamięci pochodzą z jednego oddziału i pytanie jest dlaczego zużycie pamięci jest tak wysoka, jeśli oryginalne profilowanie sterty wykazało normalne zużycie. Jeśli spojrzysz na przykład, zobaczysz dlaczego. W celu przydzielenia użyłem posix_memalign
, aby upewnić się, że alokacje trafiają do przydatnych granic. Ten alokator został następnie przekazany z klasy zewnętrznej do zmiennych wewnętrznych (w tym przypadku mapa), aby użyć alokatora do alokacji sterty. Jednak granica, którą wybrałem, była zbyt duża - 4096 - w moim przypadku. Oznacza to, że przydzielisz 4b przy użyciu posix_memalign
, ale system przydzieli całą stronę, abyś mógł ją poprawnie wyrównać. Jeśli teraz przydzielisz wiele małych wartości, otrzymasz mnóstwo nieużywanej pamięci. Ta pamięć nie zostanie zgłoszona przez zwykłe narzędzia do profilowania sterty, ponieważ alokujesz tylko ułamek tej pamięci, ale procedury alokacji systemu przydzieliją więcej i ukryją resztę.
Aby rozwiązać ten problem, przełączyłem się na mniejszą granicę i mogłem radykalnie zmniejszyć obciążenie pamięci.
Jako zakończenie moich godzin spędzonych przed Massifem & Co mogę tylko polecić, aby użyć tego narzędzia do głębokiego profilowania, ponieważ daje bardzo dobre zrozumienie tego, co się dzieje i pozwala łatwo śledzić błędy. W przypadku korzystania z posix_memalign
sytuacja jest inna. Zdarzają się przypadki, w których jest to naprawdę konieczne, jednak w większości przypadków wszystko będzie dobrze z normalnym malloc
.
Czy różnica może wynikać z samego valgrind? –
Zebrałem rozmiary OZE i PSS, gdy nie używam Valgrind lub gperftools, więc nie. – grundprinzip
'RES - Wielkość rezydentna (kb) Pamięć fizyczna, która nie została zamieniona, zadanie zostało użyte" Głupie pytanie, jak sądzę, ale czy funkcja bezpłatna() zawsze redukuje OZE? Inny facet również ma podobne problemy, jak sądzę, na http://stackoverflow.com/questions/12262146/free-can-not-release-the-mem-and-decrease-the-value-of-res-column-of- top –