Mam długo działający skrypt, który, jeśli zostanie uruchomiony wystarczająco długo, zajmie całą pamięć w moim systemie.
Nie wdając się w szczegóły scenariusza, mam dwa pytania:
- Czy są jakieś „sprawdzone metody”, których należy przestrzegać, które pomogą zapobiegać wyciekom?
- Jakie są techniki debugowania wycieków pamięci w Pythonie?
python
debugging
memory-management
memory-leaks
Fragsworth
źródło
źródło
__del__
metodami, do których nie ma już odniesień, z wyjątkiem ich cyklu. Cyklu nie można przerwać z powodu problemów z__del__
. Napraw to!Odpowiedzi:
Przeczytaj ten artykuł: Śledzenie wycieków pamięci w języku Python
Należy również zauważyć, że moduł czyszczenia pamięci może mieć ustawione flagi debugowania. Spójrz na
set_debug
funkcję. Dodatkowo spójrz na ten kod Gnibblera, aby określić typy obiektów, które zostały utworzone po wywołaniu.źródło
Wypróbowałem większość wymienionych wcześniej opcji, ale ten mały i intuicyjny pakiet okazał się najlepszy: pympler
Śledzenie obiektów, które nie zostały zebrane jako śmieci, jest dość proste, sprawdź ten mały przykład:
zainstaluj pakiet za pośrednictwem
pip install pympler
Dane wyjściowe pokazują wszystkie dodane obiekty oraz ilość zużytej przez nie pamięci.
Przykładowe dane wyjściowe:
Ten pakiet zawiera szereg dodatkowych funkcji. Zapoznaj się z dokumentacją pymplera , w szczególności z rozdziałem Identyfikacja wycieków pamięci .
źródło
pympler
może to być WOLNE . Jeśli robisz coś częściowo w czasie rzeczywistym, może to całkowicie sparaliżować wydajność aplikacji.Polecam narzędzie mem_top , które stworzyłem
Pomogło mi to rozwiązać podobny problem
Po prostu natychmiast pokazuje głównych podejrzanych o wycieki pamięci w programie w języku Python
źródło
Moduł Tracemalloc został zintegrowany jako moduł wbudowany począwszy od Pythona 3.4 i najwyraźniej jest również dostępny dla wcześniejszych wersji Pythona jako biblioteka innej firmy (chociaż go nie testowałem).
Ten moduł jest w stanie wyświetlać dokładne pliki i wiersze, które przydzieliły najwięcej pamięci. IMHO, ta informacja jest nieskończenie cenniejsza niż liczba przydzielonych instancji dla każdego typu (co kończy się na wielu krotkach w 99% przypadków, co jest wskazówką, ale w większości przypadków ledwo pomaga).
Polecam użycie tracemalloc w połączeniu z piryzytem . 9 razy na 10, uruchomienie 10 najlepszych fragmentów w powłoce pirazytu dostarczy Ci wystarczających informacji i wskazówek, jak naprawić wyciek w ciągu 10 minut. Jeśli jednak nadal nie możesz znaleźć przyczyny wycieku, skorupa pirazytu w połączeniu z innymi narzędziami wymienionymi w tym wątku prawdopodobnie da ci więcej wskazówek. Powinieneś także przyjrzeć się wszystkim dodatkowym pomocnikom zapewnianym przez pirasyt (takim jak przeglądarka pamięci).
źródło
W szczególności powinieneś spojrzeć na swoje globalne lub statyczne dane (dane długo żyjące).
Kiedy te dane rosną bez ograniczeń, możesz również mieć problemy w Pythonie.
Garbage collector może zbierać tylko dane, do których już się nie odwołuje. Jednak dane statyczne mogą łączyć elementy danych, które powinny zostać zwolnione.
Innym problemem mogą być cykle pamięci, ale przynajmniej w teorii Garbage collector powinien znaleźć i wyeliminować cykle - przynajmniej tak długo, jak długo nie są one uzależnione od jakichś długowiecznych danych.
Jakie rodzaje długowiecznych danych są szczególnie kłopotliwe? Przyjrzyj się dobrze listom i słownikom - mogą rosnąć bez ograniczeń. W słownikach możesz nawet nie zauważyć nadchodzących problemów, ponieważ kiedy korzystasz z dyktowania, liczba kluczy w słowniku może nie być dla ciebie zbyt widoczna ...
źródło
Aby wykryć i zlokalizować wycieki pamięci dla długotrwałych procesów, np. W środowiskach produkcyjnych, możesz teraz użyć stackimpact . Używa tracemalloc pod spodem. Więcej informacji w tym poście .
źródło
Jeśli chodzi o najlepsze praktyki, miej oko na funkcje rekurencyjne. W moim przypadku napotkałem problemy z rekurencją (gdzie nie było takiej potrzeby). Uproszczony przykład tego, co robiłem:
działanie w ten sposób rekurencyjny nie wyzwoli wyrzucania elementów bezużytecznych i nie usunie pozostałości funkcji, więc za każdym razem użycie pamięci rośnie i rośnie.
Moim rozwiązaniem było wyciągnięcie rekurencyjnego wywołania z funkcji my_function () i posiadanie uchwytu main (), kiedy wywołać je ponownie. w ten sposób funkcja kończy się naturalnie i oczyszcza po sobie.
źródło
Nie jestem pewien co do „Najlepszych praktyk” dotyczących wycieków pamięci w Pythonie, ale Python powinien wyczyścić swoją własną pamięć przez swój moduł odśmiecania pamięci. Więc głównie zacząłbym od sprawdzania okólnej listy jakichś krótkich, ponieważ nie zostaną one odebrane przez śmieciarza.
źródło
Nie jest to bynajmniej rada wyczerpująca. Ale najważniejszą rzeczą, o której należy pamiętać, pisząc z myślą o unikaniu przyszłych wycieków pamięci (pętli), jest upewnienie się, że wszystko, co akceptuje odwołanie do wywołania zwrotnego, powinno przechowywać to wezwanie jako słabe odniesienie.
źródło