Wiele razy miałem wycieki pamięci. Zwykle kiedy - malloc
jakby nie było jutra, albo wiszące FILE *
jak brudne pranie. Ogólnie zakładam (czytaj: mam nadzieję), że cała pamięć jest czyszczona przynajmniej po zakończeniu działania programu. Czy są jakieś sytuacje, w których wyciekająca pamięć nie zostanie zebrana po zakończeniu działania programu lub awarii?
Jeśli odpowiedź różni się znacznie w zależności od języka, skupmy się na C (++).
Zwróć uwagę na hiperboliczne użycie wyrażenia „jakby nie było jutra” i „dyndające ... jak brudne pranie”. Niebezpieczne * malloc
* może zranić tych, których kochasz. Należy również zachować ostrożność przy brudnym praniu.
c++
c
memory
memory-leaks
DilithiumMatrix
źródło
źródło
calloc
być jutra. Doskonały.Odpowiedzi:
Nie. Systemy operacyjne zamykają wszystkie zasoby przechowywane przez procesy.
Dotyczy to wszystkich zasobów, które utrzymuje system operacyjny: pamięci, otwartych plików, połączeń sieciowych, uchwytów okien ...
To powiedziawszy, jeśli program działa w systemie wbudowanym bez systemu operacyjnego lub z bardzo prostym lub błędnym systemem operacyjnym, pamięć może być bezużyteczna do czasu ponownego uruchomienia. Ale gdybyś był w takiej sytuacji, prawdopodobnie nie zadawałbyś tego pytania.
Zwolnienie niektórych zasobów przez system operacyjny może zająć dużo czasu. Na przykład port TCP używany przez serwer sieciowy do akceptowania połączeń może zająć kilka minut, zanim zostanie zwolniony, nawet jeśli zostanie poprawnie zamknięty przez program. Program sieciowy może również przechowywać zdalne zasoby, takie jak obiekty bazy danych. System zdalny powinien zwolnić te zasoby w przypadku utraty połączenia sieciowego, ale może to potrwać nawet dłużej niż lokalny system operacyjny.
źródło
ipcrm
możliwość ręcznego czyszczenia linux.die.net/man/8/ipcrm .Standard C nie określa, że pamięć przydzielona przez
malloc
jest zwalniana po zakończeniu programu. Jest to wykonywane przez system operacyjny, a nie wszystkie systemy operacyjne (zazwyczaj są to systemy wbudowane), zwalniają pamięć po zakończeniu działania programu.źródło
main
zwraca,malloc
zwalniana jest cała pamięć przydzielona przez . Na przykład mówi, że wszystkie otwarte pliki są zamykane przed zakończeniem programu. W przypadku pamięci przydzielonej mymalloc
po prostu nie jest określony. Teraz, oczywiście, moje zdanie dotyczące systemu operacyjnego opisuje to, co zwykle się robi, a nie to, co zaleca norma, ponieważ nie określa niczego na ten temat.std::atexit
rozważa również zakończenie programu za pośrednictwemstd::exit
, a następnie jest równieżstd::abort
i (specyficzne dla C ++)std::terminate
.atexit
nie byłoby użyteczne. :-)Ponieważ wszystkie odpowiedzi obejmowały większość aspektów twojego pytania we współczesnych systemach operacyjnych, ale historycznie jest jeden, o którym warto wspomnieć, jeśli kiedykolwiek programowałeś w świecie DOS. Programy rezydenta terminanta i pobytu (TSR) zwykle zwracałyby kontrolę do systemu, ale rezydowałyby w pamięci, która mogłaby zostać przywrócona przez przerwanie programowe / sprzętowe. Podczas pracy na tych systemach operacyjnych pojawiały się komunikaty typu „brak pamięci! Spróbuj wyładować niektóre programy TSR” .
Z technicznego punktu widzenia program się kończy , ale ponieważ nadal rezyduje w pamięci, żaden wyciek pamięci nie zostałby zwolniony, chyba że wyładujesz program.
Możesz więc uznać to za inny przypadek, z wyjątkiem systemów operacyjnych, które nie odzyskują pamięci, ponieważ jest wadliwy lub ponieważ wbudowany system operacyjny jest do tego zaprojektowany.
Pamiętam jeszcze jeden przykład. Customer Information Control System (CICS), serwer transakcji, który działa głównie na komputerach mainframe IBM, jest pseudo-konwersacyjny. Po wykonaniu przetwarza dane wprowadzone przez użytkownika, generuje inny zestaw danych dla użytkownika, przesyłając je do węzła końcowego użytkownika i kończy pracę. Po aktywacji klawisza uwagi ponownie ożywia się, aby przetworzyć inny zestaw danych. Ze względu na sposób, w jaki zachowuje się, ponownie pod względem technicznym, system operacyjny nie odzyska pamięci z zakończonych programów CICS, chyba że ponownie uruchomisz serwer transakcji CICS.
źródło
Jak powiedzieli inni, większość systemów operacyjnych odzyskuje przydzieloną pamięć po zakończeniu procesu (i prawdopodobnie inne zasoby, takie jak gniazda sieciowe, uchwyty plików itp.).
Powiedziawszy to, pamięć może nie być jedyną rzeczą, o którą musisz się martwić, gdy masz do czynienia z nowym / usuń (zamiast surowego malloc / free). Pamięć przydzielona w new może zostać odzyskana, ale rzeczy, które można zrobić w destruktorach obiektów, nie będą miały miejsca. Być może destruktor jakiejś klasy zapisuje wartość wartowniczą do pliku po zniszczeniu. Jeśli proces właśnie się zakończy, uchwyt pliku może zostać opróżniony, a pamięć odzyskana, ale ta wartość wartownicza nie zostanie zapisana.
Morał z tej historii, zawsze posprzątaj po sobie. Nie pozwól, by coś się zwisało. Nie polegaj na czyszczeniu systemu operacyjnego po tobie. Posprzątaj po sobie.
źródło
kill -9
pojawi się jakiś mniej niż błyskotliwy fan ...)std::exit
wezwie lekarzy,std::abort
nie zrobi, niechętne wyjątki mogą.Zależy to raczej od systemu operacyjnego niż języka. Ostatecznie każdy program w dowolnym języku otrzyma swoją pamięć z systemu operacyjnego.
Nigdy nie słyszałem o systemie operacyjnym, który nie odzyskuje pamięci, gdy program kończy pracę / ulega awarii. Więc jeśli twój program ma górną granicę pamięci, którą musi przydzielić, to samo przydzielanie i nigdy nie zwalnianie jest całkowicie uzasadnione.
źródło
Jeśli program zostanie kiedykolwiek przekształcony w komponent dynamiczny („wtyczkę”), który jest ładowany do przestrzeni adresowej innego programu, będzie to kłopotliwe, nawet w systemie operacyjnym z uporządkowanym zarządzaniem pamięcią. Nie musimy nawet myśleć o przeniesieniu kodu do mniej wydajnych systemów.
Z drugiej strony zwolnienie całej pamięci może wpłynąć na wydajność czyszczenia programu.
Jeden program, nad którym pracowałem, wymagał 30 sekund lub więcej, aby program się zakończył, ponieważ powtarzał się przez wykres całej pamięci dynamicznej i zwalniał ją kawałek po kawałku.
Rozsądnym rozwiązaniem jest posiadanie tam możliwości i objęcie ich przypadkami testowymi, ale wyłączenie ich w kodzie produkcyjnym, aby aplikacja szybko kończyła pracę.
źródło
Wszystkie systemy operacyjne zasługujące na ten tytuł posprzątają bałagan spowodowany przez proces po zakończeniu. Ale zawsze zdarzają się nieprzewidziane zdarzenia, co by było, gdyby jakoś odmówiono mu dostępu, a jakiś biedny programista nie przewidział takiej możliwości i nie próbuje ponownie trochę później? Zawsze bezpieczniej jest po prostu oczyścić się, JEŚLI wycieki pamięci są krytyczne - w przeciwnym razie nie jest to naprawdę warte wysiłku IMO, jeśli wysiłek ten jest kosztowny.
Edycja: musisz wyczyścić wycieki pamięci, jeśli znajdują się w miejscu, w którym będą się gromadzić, jak w pętlach. Wycieki pamięci, o których mówię, to te, które narastają w ciągłym czasie w trakcie programu, jeśli masz wyciek jakiegokolwiek innego rodzaju, najprawdopodobniej wcześniej czy później będzie to poważny problem.
Z technicznego punktu widzenia, jeśli wycieki mają „złożoność” pamięci O (1), w większości przypadków są w porządku, O (logn) już nieprzyjemne (aw niektórych przypadkach śmiertelne) i O (N) + nie do zniesienia.
źródło
Pamięć współdzielona w systemach zgodnych z POSIX utrzymuje się do momentu wywołania shm_unlink lub ponownego uruchomienia systemu.
źródło
Jeśli masz komunikację międzyprocesową, może to prowadzić do tego, że inne procesy nigdy nie będą kończyć i zużywać zasobów w zależności od protokołu.
Dla przykładu, kiedyś eksperymentowałem z drukowaniem na drukarce PDF w Javie, kiedy zamykałem JVM w środku zadania drukarki, proces buforowania PDF pozostał aktywny i musiałem go zabić w menedżerze zadań, zanim mogłem ponów próbę drukowania.
źródło