Co to są bajty prywatne, bajty wirtualne, zestaw roboczy?

490

Próbuję użyć narzędzia systemu Windows perfmon do debugowania wycieków pamięci w procesie.

Oto jak perfmon wyjaśnia terminy:

Zestaw roboczy to bieżący rozmiar zestawu roboczego tego procesu (w bajtach). Zestaw roboczy to zestaw stron pamięci dotkniętych ostatnio przez wątki w tym procesie. Jeśli ilość wolnej pamięci w komputerze przekroczy próg, strony pozostaną w zestawie roboczym procesu, nawet jeśli nie są używane. Gdy ilość wolnej pamięci spadnie poniżej progu, strony są przycinane z zestawów roboczych. Jeśli będą potrzebne, zostaną z powodzeniem przywrócone do zestawu roboczego przed opuszczeniem pamięci głównej.

Wirtualne bajty to bieżący rozmiar w bajtach wirtualnej przestrzeni adresowej, z której korzysta proces. Wykorzystanie wirtualnej przestrzeni adresowej niekoniecznie oznacza odpowiednie użycie stron dysku lub pamięci głównej. Przestrzeń wirtualna jest skończona, a proces może ograniczyć jej zdolność do ładowania bibliotek.

Prywatne bajty to bieżący rozmiar w bajtach pamięci przydzielonej przez ten proces, który nie może być współużytkowany z innymi procesami.

Oto pytania, które mam:

Czy to prywatne bajty, które powinienem zmierzyć, aby upewnić się, czy w procesie występują wycieki, ponieważ nie obejmują one żadnych bibliotek współdzielonych, a wszelkie wycieki, jeśli się zdarzyły, pochodzą z samego procesu?

Jaka jest całkowita pamięć zużywana przez proces? Czy to wirtualne bajty czy suma wirtualnych bajtów i zestawu roboczego?

Czy istnieje jakikolwiek związek między prywatnymi bajtami, zestawem roboczym i wirtualnymi bajtami?

Czy są jakieś inne narzędzia, które lepiej obrazują wykorzystanie pamięci?

pankajt
źródło
3
Lepszym narzędziem byłby valgrind / helgrind, ale nie pod Windows niestety :(
Kornel Kisielewicz
Czy to jest bajt prywatny, czy powinienem zmierzyć, aby upewnić się, czy proces ma jakiś wyciek Jeśli prywatne bajty procesu nie rosną, nie ma wycieków pamięci. Jeśli wzrosną, może to wynikać z wycieków pamięci i może być spowodowane fragmentacją pamięci. Myślę, że trudno powiedzieć, patrząc na wzrost prywatnych bajtów, co to dokładnie znaczy.
@SergeiKurenkov Jedyne, co możemy powiedzieć, to NIGDY nie wynikałoby to z „fragmentacji pamięci”.
Jamie Hanrahan,

Odpowiedzi:

517

Krótka odpowiedź na to pytanie jest taka, że żadna z tych wartości nie jest wiarygodnym wskaźnikiem ilości pamięci używanej przez plik wykonywalny i żadna z nich nie jest odpowiednia do debugowania wycieku pamięci.

Bajty prywatne odnoszą się do ilości pamięci, że wykonywalny proces został poproszony o - niekoniecznie kwota jest faktycznie użyciu . Są „prywatne”, ponieważ (zwykle) wykluczają pliki mapowane w pamięci (tj. Współdzielone biblioteki DLL). Ale - oto haczyk - niekoniecznie wykluczają pamięć przydzieloną przez te pliki . Nie ma sposobu, aby stwierdzić, czy zmiana w bajtach prywatnych wynikała z samego pliku wykonywalnego, czy z dołączonej biblioteki. Prywatne bajty to nie tylko pamięć fizyczna; mogą być stronicowane na dysk lub na liście stron rezerwowych (tzn. nie są już używane, ale jeszcze nie są stronicowane).

Zestaw roboczy odnosi się do całkowitej pamięci fizycznej (RAM) używanej przez proces. Jednak w przeciwieństwie do bajtów prywatnych, obejmuje to również pliki mapowane w pamięci i różne inne zasoby, więc jest to nawet mniej dokładny pomiar niż bajty prywatne. Jest to ta sama wartość, która jest zgłaszana w „Użycie pamięci” w Menedżerze zadań i była źródłem nieskończonych ilości nieporozumień w ostatnich latach. Pamięć w zestawie roboczym jest „fizyczna” w tym sensie, że można ją rozwiązać bez błędu strony; jednak lista stron rezerwowych jest również nadal fizycznie w pamięci, ale nie jest zgłaszana w zestawie roboczym, i dlatego może się zdarzyć, że „użycie pamięci” nagle spadnie po zminimalizowaniu aplikacji.

Wirtualne bajty to całkowita wirtualna przestrzeń adresowa zajmowana przez cały proces. Przypomina to zestaw roboczy, w tym sensie, że zawiera pliki mapowane w pamięci (współdzielone biblioteki DLL), ale zawiera również dane z listy rezerwowej oraz dane, które zostały już stronicowane i znajdują się gdzieś w pliku stronicowania na dysku. Całkowita liczba bajtów wirtualnych wykorzystywanych przez każdy proces w systemie o dużym obciążeniu doda znacznie więcej pamięci niż faktycznie ma maszyna.

Relacje są więc następujące:

  • Bajty prywatne są tym, co faktycznie przydzieliła twoja aplikacja, ale obejmują użycie pliku strony;
  • Zestaw roboczy to niestronicowane prywatne bajty plus pliki mapowane w pamięci;
  • Wirtualne bajty to zestaw roboczy plus stronicowane prywatne bajty i lista rezerwowa.

Jest tu kolejny problem; tylko jako współdzielone biblioteki można przydzielić pamięci wewnątrz modułu aplikacji, co prowadzi do potencjalnych fałszywych alarmów podano w swojej aplikacji Private Bytes, Twoja aplikacja może również skończyć przydzielania pamięci wewnątrz wspólnych modułów, co prowadzi do fałszywych negatywów . Oznacza to, że w rzeczywistości aplikacja może mieć wyciek pamięci, który nigdy nie objawia się w prywatnych bajtach. Mało prawdopodobne, ale możliwe.

Prywatne bajty są rozsądnym przybliżeniem ilości pamięci używanej przez plik wykonywalny i mogą być wykorzystane do zawężenia listy potencjalnych kandydatów na wyciek pamięci; jeśli zauważysz, że liczba ta stale rośnie i rośnie w nieskończoność, warto sprawdzić ten proces pod kątem wycieków. Nie może to jednak udowodnić, że istnieje wyciek lub nie.

Jednym z najbardziej skutecznych narzędzi do wykrywania / korygowania wycieków pamięci w systemie Windows jest w rzeczywistości Visual Studio (link prowadzi do strony dotyczącej używania VS do wycieków pamięci, a nie do strony produktu). Racjonalne oczyszczenie to kolejna możliwość. Microsoft ma również bardziej ogólny dokument dotyczący najlepszych praktyk na ten temat. Istnieje więcej narzędzi wymienionych w poprzednim pytaniu .

Mam nadzieję, że to wyjaśni kilka rzeczy! Śledzenie wycieków pamięci jest jedną z najtrudniejszych rzeczy do zrobienia podczas debugowania. Powodzenia.

Aaronaught
źródło
26
Obawiam się, że odpowiedź nie jest całkiem poprawna. Prywatne bajty odnoszą się do ilości pamięci (RAM), o którą prosi plik wykonywalny procesu - nie tylko pamięci fizycznej. W ten sposób możesz z pewnością sprawdzić większość przypadków wycieków pamięci, monitorując prywatne bajty. Spróbuj :: VisualAlloc, aby zatwierdzić dużą część pamięci (powiedzmy 1,5G). Powinieneś być w stanie zobaczyć, że twoje prywatne bajty są znacznie większe niż zestaw roboczy. Co dowodzi, że „Zestaw roboczy to bajty prywatne plus pliki mapowane w pamięci” jest niepoprawny.
Jay Zhu,
4
Właściwie uważam, że zapis jest następujący: „Zestaw roboczy to prywatne bajty w pamięci plus pliki mapowane w pamięci”. A prywatne bajty MOGĄ zostać zamienione - możesz zobaczyć prywatne bajty większe niż pamięć fizyczna, którą masz w urządzeniu.
Jay Zhu,
2
@Aaronaught: Twoje pierwsze stwierdzenie o niezawodnym wskaźniku i odpowiednim do debugowania jest mylące. Prywatne bajty to niezawodny wskaźnik przecieku pamięci aplikacji. Może to być zależna i pośrednia biblioteka DLL, ale jest to wyciek w pamięci aplikacji. Czy możesz wyjaśnić, dlaczego nie można go użyć do debugowania? pełny zrzut pamięci procesu aplikacji powinien poinformować nas, co zużywa tę pamięć. Nie jestem pewien, czy rozumiem, dlaczego nie można go użyć do debugowania. Czy możesz rzucić trochę światła?
G33kKahuna
@ G33kKahuna: Nie jest dla mnie jasne, jak zrzut pamięci powiedziałby ci, co zużywa pamięć w jakimkolwiek sensownym sensie - chyba że przez „co” masz na myśli „jakie moduły”, ale wtedy wszystko, co masz, to migawka, nadal nie możesz zobaczyć który moduł faktycznie przecieka pamięć w czasie, chyba że wykonasz kilka zrzutów w czasie i pod ściśle kontrolowanymi warunkami. Trudno wyobrazić sobie bardziej nieefektywną i niewiarygodną strategię debugowania. Obecnie profilerzy są wszędzie; użyj jednego.
Aaronaught
1
Uruchom pełny! Objsize, powinien pokazać wszystkie przypięte obiekty w bezpośrednim stosie. Możesz to potwierdzić, zaznaczając eeheap -gc. Powinno to pokazać, gdzie zablokowano głośność. Zazwyczaj, jeśli żadne wskazówki nie są dostępne dla wszystkich powyższych poleceń, twoje prywatne bajty są zużywane przez niepobrane obiekty w GC. Teraz przejdź do gchandles lub gcleaks. Te polecenia powinny powiedzieć, jakiego typu / adresu obiektu nie można zmapować. Wskaźnik wciąż tam jest, ale obiekt zniknął. Jest to taki kategoryczny problem dla niewydanych programów obsługi zdarzeń.
G33kKahuna
10

Nie powinieneś próbować używać perfmon, menedżera zadań ani żadnego takiego narzędzia do określania wycieków pamięci. Są dobre do identyfikowania trendów, ale niewiele więcej. Liczby, które zgłaszają w wartościach bezwzględnych, są zbyt niejasne i zagregowane, aby były użyteczne w przypadku konkretnego zadania, takiego jak wykrywanie wycieków pamięci.

Poprzednia odpowiedź na to pytanie doskonale wyjaśniła, jakie są różne typy.

Pytasz o rekomendację narzędzia: Polecam Memory Validator. Może monitorować aplikacje, które dokonują miliardów alokacji pamięci.

http://www.softwareverify.com/cpp/memory/index.html

Oświadczenie: Zaprojektowałem Walidator pamięci.

Stephen Kellett
źródło
1
Nie mogę nawet uruchomić prostego pliku klasy (w Javie)? Co daje?
jn1kk
Podejrzewam, że Stephen i Devil są w jakiś sposób spokrewnieni lub nawet sklonowani ...: D;)
Robert Koritnik
@StephenKellett, Czy jest wersja próbna?
Pacerier,
@Pacerier, jeśli podążysz za linkiem, istnieje wersja próbna dla wersji x86 i x64 tuż nad opcją kup po lewej stronie.
Bradley A. Tetreault
10

Definicja liczników perfmon jest od początku niepoprawna i z jakiegoś powodu wydaje się zbyt trudna do poprawienia.

Dobry przegląd zarządzania pamięcią systemu Windows jest dostępny w filmie „ Mysteries of Memory Management Revealed ” na MSDN: Obejmuje on więcej tematów niż jest to potrzebne do śledzenia wycieków pamięci (np. Zarządzanie zestawem roboczym), ale zawiera wystarczającą ilość szczegółów w odpowiednich tematach.


Aby dać ci wskazówkę dotyczącą problemu z opisami liczników perfmon, oto wewnętrzna historia o bajtach prywatnych z „ Licznika wydajności prywatnych bajtów - Uwaga! ” Na MSDN:

P: Kiedy prywatny bajt nie jest prywatnym bajtem?

Odp .: Gdy nie jest rezydentem.

Licznik Prywatne bajty zgłasza opłatę zatwierdzenia procesu. Oznacza to, że ilość miejsca przydzielonego w pliku wymiany do przechowywania zawartości pamięci prywatnej w przypadku jej zamiany. Uwaga: unikam słowa „zarezerwowany” z powodu możliwego pomylenia z pamięcią wirtualną w stanie zarezerwowanym, który nie został popełniony.


Z „ Planowania wydajności ” w MSDN:

3.3 Bajty prywatne

3.3.1 Opis

Pamięć prywatna jest definiowana jako pamięć przydzielona procesowi, który nie może być współużytkowany przez inne procesy. Ta pamięć jest droższa niż pamięć współdzielona, ​​gdy wiele takich procesów jest wykonywanych na komputerze. Prywatna pamięć w (tradycyjnych) niezarządzanych bibliotekach DLL zwykle składa się ze statyki C ++ i jest rzędu 5% całkowitego zestawu roboczego biblioteki DLL.

znak
źródło
1
głosuj z powodu niesamowicie dobrych przykładów na to, jak się psuje!
Bruno Brant,
Pierwszy cytat jest błędny. Przydzielenie „Prywatnych bajtów” nie wymaga „przydzielenia niczego w pliku wymiany” (który tak naprawdę nazywa się plikiem stronicowania). Nie trzeba nawet mieć pliku stronicowania, aby można było przypisać „prywatne bajty”. W rzeczywistości, przeznaczając prywatnych bajtów nie od razu wykorzystać każdą przestrzeń nigdzie i nigdy nie mogą używać jak została przydzielona.
Jamie Hanrahan,
Drugi cytat nie jest dużo lepszy. Prywatne bajty używane w kodzie DLL niekoniecznie są w większości statycznie przydzielane w bibliotece DLL. Kod DLL jest całkowicie darmowy do wywoływania VirtualAlloc, HeapAlloc (malloc i nowy w CRTL) itp. Próbuje również opisać wielkość pamięci prywatnej jako procent wielkości zestawu roboczego, co jest nonsensowne. Pierwszy z nich ma rozmiar wirtualny (i będzie taki sam dla każdego użycia kodu z tym samym wejściem), podczas gdy drugi jest fizyczny (który może się radykalnie różnić od jednego uruchomienia do drugiego, w zależności od tego, ile pamięci jest bogatej lub - maszyna głoduje).
Jamie Hanrahan,
5

Tutaj jest ciekawa dyskusja: http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/307d658a-f677-40f2-bdef-e6352b0bfe9e/ Rozumiem ten wątek, że zwalnianie małych przydziałów jest nie odzwierciedlone w prywatnych bajtach lub zestawie roboczym.

Krótko mówiąc:

jeśli zadzwonię

p=malloc(1000);
free(p);

wtedy Bajty Prywatne odzwierciedlają tylko przydział, a nie dezalokację.

jeśli zadzwonię

p=malloc(>512k);
free(p);

wtedy Bajty Prywatne poprawnie odzwierciedlają przydział i dezalokację.

Mcanti
źródło
7
Wyjaśnia to fakt, że standardowe funkcje pamięci biblioteki C używają niestandardowego lub Win32 Heap, który jest mechanizmem zarządzania pamięcią na niskim poziomie zarządzania pamięcią na poziomie procesu.
Kyberias
@ Kyberias, więc jak się dostać poniżej ?
Pacerier
podczas gdy (1) wolny (malloc (1000)); // Czy spowodowałoby to wzrost prywatnych bajtów na zawsze?
franckspike,
2
@franckspike: nie, wzrośnie do pewnego punktu (zwykle około 4 kB, ale może się różnić), a następnie zatrzyma się, ponieważ CRT ponownie użyje poprzednio zwolnionej pamięci zamiast żądać nowych stron z systemu operacyjnego.
Miral
@Pacerier: Możesz wywołać VirtualAlloc i VirtualFree.
Jamie Hanrahan,