Czy wycieki pamięci są w porządku? [Zamknięte]

231

Czy kiedykolwiek dopuszczalne jest wycieki pamięci w aplikacji C lub C ++?

Co się stanie, jeśli przydzielisz trochę pamięci i wykorzystasz ją do ostatniego wiersza kodu w aplikacji (na przykład destruktora obiektu globalnego)? O ile zużycie pamięci nie rośnie z czasem, czy można ufać systemowi operacyjnemu, który zwolni twoją pamięć po zakończeniu aplikacji (w systemach Windows, Mac i Linux)? Czy uznałbyś to za prawdziwy wyciek pamięci, gdyby pamięć była używana nieprzerwanie, dopóki nie zostanie zwolniona przez system operacyjny.

Co jeśli biblioteka innej firmy wymusi na tobie taką sytuację? Czy odmówiłby korzystania z tej biblioteki strony trzeciej, bez względu na to, jak świetna byłaby w przeciwnym razie?

Widzę tylko jedną praktyczną wadę, a mianowicie to, że te łagodne wycieki pojawią się wraz z narzędziami do wykrywania wycieków pamięci jako fałszywie pozytywne.

Imbue
źródło
50
Jeśli zużycie pamięci nie rośnie z czasem, nie jest to wyciek.
mpez0,
4
Większość aplikacji (w tym wszystkie programy .NET) ma co najmniej kilka buforów, które są przydzielane raz i nigdy nie są jawnie zwalniane. Dlatego definicja mpez0 jest bardziej przydatna.
Ben Voigt,
2
Tak, jeśli masz nieskończoną pamięć.
użytkownik
„Łagodny” wyciek (jeśli istnieje) nie jest fałszywie dodatni - jest to wyciek, który został bardzo poprawnie wykryty. Detekcja wycieków, nawet w przypadku wycieków, których osobiście nie masz ochoty na naprawę, jest jedynym powodem wykrycia wycieków.
cHao,
1
@ mpez0 „Jeśli zużycie pamięci nie rośnie z czasem, to nie jest to przeciek”? To nie jest definicja wycieku pamięci. Wyciek to pamięć, która została wyciekła, co oznacza, że ​​nie została uwolniona i nie masz już do niej odniesienia, dlatego nie jest możliwe, abyś kiedykolwiek ją ponownie uwolnił. Nie ma znaczenia, czy rośnie, czy nie.
Mecki,

Odpowiedzi:

329

Nie.

Jako profesjonaliści pytanie, którego nie powinniśmy sobie zadawać, brzmi: „Czy to jest w porządku?” ale raczej „Czy kiedykolwiek jest ku temu dobry powód?” A „polowanie na wyciek pamięci to ból” nie jest dobrym powodem.

Lubię upraszczać sprawy. I prosta zasada jest taka, że ​​mój program nie powinien mieć wycieków pamięci.

To też sprawia, że ​​moje życie jest proste. Jeśli wykryję wyciek pamięci, eliminuję go, zamiast przeglądać skomplikowaną strukturę drzewa decyzyjnego w celu ustalenia, czy jest to „akceptowalny” wyciek pamięci.

Jest podobny do ostrzeżeń kompilatora - czy ostrzeżenie będzie śmiertelne dla mojej konkretnej aplikacji? Może nie.

Ale ostatecznie jest to kwestia dyscypliny zawodowej. Tolerowanie ostrzeżeń kompilatora i tolerowanie wycieków pamięci to zły nawyk, który ostatecznie ugryzie mnie w tył.

Mówiąc ekstremalnie, czy chirurg byłby w stanie pozostawić pacjentowi jakiś sprzęt operacyjny?

Chociaż możliwe jest, że zaistnieje sytuacja, w której koszt / ryzyko usunięcia tego sprzętu przewyższy koszt / ryzyko pozostawienia go, i mogą zaistnieć sytuacje, w których byłby nieszkodliwy, gdybym zobaczył to pytanie opublikowane na SurgeonOverflow.com i zobaczył jakąkolwiek odpowiedź inną niż „nie”, poważnie podważyłoby to moje zaufanie do zawodu lekarza.

-

Gdyby biblioteka trzeciej strony wymusiła na mnie tę sytuację, doprowadziłbym do poważnego podejrzenia ogólnej jakości danej biblioteki. Byłoby tak, jakbym jechał samochodem testowym i znalazł kilka luźnych podkładek i nakrętek w jednym z uchwytów na kubki - sam w sobie może to nie być wielka sprawa, ale obrazuje brak przywiązania do jakości, więc rozważę alternatywy.

JohnMcG
źródło
57
Prawda i nieprawda w tym samym czasie. Ostateczna większość z nas to niewolnicy najemni, a wszelkie pragnienie kunsztu musi zająć miejsce w stosunku do wymagań firmy. Jeśli w bibliotece innej firmy jest wyciek i oszczędzasz 2 tygodnie pracy, może istnieć uzasadnienie biznesowe, aby z niej skorzystać itp.
Cervo,
3
Tak czy inaczej skorzystałbym z biblioteki, gdyby było to coś, czego potrzebowałem i nie istniałyby przyzwoite alternatywy, ale logowałbym błąd z opiekunami.
tloach
7
Chociaż osobiście wybrałbym dokładnie tę samą odpowiedź, istnieją programy, które prawie nie zwalniają pamięci. Powodem jest to, że a) są przeznaczone do działania w systemach operacyjnych, które zwalniają pamięć, oraz b) zaprojektowane tak, aby nie działały zbyt długo. Rzeczywiście rzadkie ograniczenia dla programu, ale akceptuję to jako całkowicie poprawne.
2
Aby dodać kilka powodów wczesnego sprawdzania: kiedy twoje narzędzia do debugowania zostaną zalane „łagodnymi” przeciekami, jak znajdziesz „prawdziwy”? Jeśli dodasz funkcję wsadową i nagle wyciek 1 K / godzinę stanie się 1 K / sekundę?
peterchen
5
Hmm, czy „nie wyciek pamięci” jest „idealny”?
JohnMcG,
80

Nie uważam tego za wyciek pamięci, chyba że ilość „używanej” pamięci ciągle rośnie. Niewielka pamięć, choć nie idealna, nie stanowi dużego problemu, chyba że ilość wymaganej pamięci ciągle rośnie.

Jim C.
źródło
12
Technicznie przeciek jest alokowaną pamięcią i wszystkie odniesienia do niej są tracone. Nie cofanie przydziału pamięci na końcu jest po prostu leniwe.
Martin York,
17
Jeśli masz jednorazowy przeciek pamięci o wielkości 4 GB, to problem.
John Dibling,
21
Nie ma znaczenia, czy rośnie, czy nie. Inne programy nie mogą korzystać z pamięci, jeśli ją masz.
Bill the Lizard
8
> Inne programy nie mogą korzystać z pamięci, jeśli została ona przydzielona. Cóż, system operacyjny może zawsze zamienić pamięć na dysk i pozwolić innym aplikacjom na użycie pamięci RAM, z której nie korzystałeś.
Max Lybbert,
4
Jeśli program jest bardzo krótkotrwały, wyciek może nie być tak zły. Ponadto, chociaż NIE jest to idealne, stronicowanie nie jest tak drogie, jak niektórzy się tutaj okazują, ponieważ program nie jest zainteresowany tą pamięcią (i dlatego nie będzie zamieniał się cały czas) - chyba że oczywiście masz GC ...
Arafangion
79

Najpierw poprawmy nasze definicje. Wyciek pamięci występuje, gdy pamięć jest dynamicznie przydzielana, np. Za pomocą malloc(), i wszystkie odniesienia do pamięci są tracone bez odpowiedniego wolnego. Łatwy sposób na zrobienie tego jest taki:

#define BLK ((size_t)1024)
while(1){
    void * vp = malloc(BLK);
}

Zauważ, że za każdym razem w pętli while (1) przydzielane są 1024 bajty (+ narzut), a nowy adres jest przypisywany do vp; nie ma żadnego wskaźnika do poprzednich bloków Malloc'ed. Ten program będzie działał do momentu wyczerpania stosu i nie ma możliwości odzyskania żadnej pamięci malloc'ed. Pamięć „wycieka” ze sterty, nigdy więcej nie będzie widoczna.

Jednak to, co opisujesz, brzmi

int main(){
    void * vp = malloc(LOTS);
    // Go do something useful
    return 0;
}

Przydzielasz pamięć i pracujesz z nią do momentu zakończenia programu. To nie jest wyciek pamięci; nie wpływa to negatywnie na program, a cała pamięć zostanie automatycznie oczyszczona po zakończeniu programu.

Zasadniczo należy unikać wycieków pamięci. Po pierwsze, ponieważ podobnie jak wysokość nad tobą i zapasy paliwa w hangarze, pamięć, która wyciekła i nie można jej odzyskać, jest bezużyteczna; po drugie, o wiele łatwiej jest poprawnie zakodować, nie przeciekając pamięci na początku, niż później znaleźć przeciek pamięci.

Charlie Martin
źródło
Rozważmy teraz kilkadziesiąt takich przydziałów. Teraz rozważ przeniesienie „głównego” ciała do procedury, która jest wywoływana wiele razy. Cieszyć się. - Zgadzam się z opinią, że w tym scenariuszu nie ma tak dużego problemu, ale scenariusze się zmieniają. Jak mówią, zawsze pisz kod, jakby facet, który go utrzymuje, wiedział, gdzie mieszkasz.
peterchen
2
Chodzi o to, że pamięć jest malloc'ed i utrzymywana, dopóki program nie wywoła _exit () nie jest „wyciekły”.
Charlie Martin
1
Jest to wyciek pamięci i może uszkodzić twój program. Przyszłe przydziały mogą się nie powieść z tego procesu, ponieważ jestem pewien, że sprawdzasz, czy malloc zwrócił wszędzie zero. nadmierne wykorzystanie pamięci, na przykład w sytuacji, w której pamięci jest mało, może być różnicą między życiem a śmiercią.
MikeJ
10
Mike, to po prostu nieprawda. W zgodnym środowisku C zakończenie main uwalnia wszystkie zasoby procesu. W środowisku osadzonym, takim jak opisujesz, możesz zobaczyć tę sytuację, ale nie miałbyś głównej. Przyznaję, że mogą istnieć wadliwe środowiska osadzone, dla których nie byłoby to prawdą, ale wtedy widziałem wadliwe środowiska, które nie radziłyby sobie z + = poprawnie.
Charlie Martin
3
Tak, odkryłeś teraz, że jeśli masz mallocza dużo pamięci, jest to Zła Rzecz. To wciąż nie jest wyciek . To nie jest przeciek, dopóki mallocpamięć nie zostanie utracona.
Charlie Martin
39

Teoretycznie nie, w praktyce to zależy .

To naprawdę zależy od tego, na ile danych pracuje program, jak często program jest uruchamiany i czy działa stale.

Jeśli mam szybki program, który odczytuje niewielką ilość danych, dokonuje obliczeń i kończy pracę, niewielki wyciek pamięci nigdy nie zostanie zauważony. Ponieważ program nie działa bardzo długo i zużywa tylko niewielką ilość pamięci, wyciek będzie niewielki i uwolniony, gdy program będzie istniał.

Z drugiej strony, jeśli mam program, który przetwarza miliony rekordów i działa przez długi czas, niewielki wyciek pamięci może sprowadzić maszynę na wystarczająco długi czas.

Jeśli chodzi o biblioteki stron trzecich, które mają wycieki, jeśli powodują problem, napraw bibliotekę lub znajdź lepszą alternatywę. Jeśli to nie powoduje problemu, czy to naprawdę ma znaczenie?

vfilby
źródło
Nie wiem, czy przeczytałeś całe moje pytanie, czy nie. Mówię, że pamięć jest używana do samego końca aplikacji. Z czasem nie rośnie. Jedyne nie, to nie to, że nie ma wezwania do zwolnienia / usunięcia.
Imbue
2
To nie jest przeciek pamięci. Wyciek pamięci to niewielkie ilości nieużywanej, ale niewykorzystanej pamięci, ilość ta z czasem wzrasta. Mówisz o kropli pamięci. Nie przejmuj się tym, chyba że twoja kropla jest bardzo duża.
vfilby,
„Jeśli to nie powoduje problemu, czy to naprawdę ma znaczenie?” Nie, to wcale nie ma znaczenia. Chciałbym, żeby więcej ludzi to otrzymało zamiast religijnych.
Imbue
2
@John: Na ogół nie jest to leniwy programista, a bardziej ewoluujące oprogramowanie. Wszyscy popełniamy błędy, robaki to nasz handel; robimy je, naprawiamy, to właśnie robimy. Zawsze jest równowaga między kosztami początkowymi a długoterminową konserwacją, która nigdy nie jest prosta.
vfilby,
1
John, w 100% się z tobą zgadzam .. Imbum Pytanie brzmi prawie: „ile akceptujesz”. Niechlujstwo jest niechlujne .. Może zostawię krewetki za monitorem. smród jest śmierdzący. Za każdym razem, gdy się jaskiniamy, nasza branża trochę się zapada. Jeśli wiesz, że jest wyciek i wiesz, że to spowodowałeś, powinieneś go naprawić.
baash05
37

Wydaje się, że wiele osób ma wrażenie, że po zwolnieniu pamięci natychmiast wraca do systemu operacyjnego i może być używana przez inne programy.

To nie jest prawda. Systemy operacyjne zwykle zarządzają pamięcią na stronach 4KiB. malloca inne rodzaje zarządzania pamięcią pobierają strony z systemu operacyjnego i zarządzają nimi podrzędnie według własnego uznania. Jest całkiem prawdopodobne, że free()będzie nie wrócić strony do systemu operacyjnego, przy założeniu, że program będzie więcej pamięci malloc później.

Nie twierdzę, że free()nigdy nie zwraca pamięci do systemu operacyjnego. Może się to zdarzyć, szczególnie jeśli uwalniasz duże obszary pamięci. Ale nie ma gwarancji.

Ważny fakt: jeśli nie zwolnisz pamięci, której już nie potrzebujesz, kolejne centra handlowe będą zużywać jeszcze więcej pamięci. Ale jeśli najpierw zwolnisz, malloc może ponownie użyć zwolnionej pamięci.

Co to oznacza w praktyce? Oznacza to, że jeśli wiesz, że twój program nie będzie odtąd wymagał więcej pamięci (na przykład jest w fazie czyszczenia), zwolnienie pamięci nie jest tak ważne. Jeśli jednak program może później przydzielić więcej pamięci, należy unikać wycieków pamięci - szczególnie takich, które mogą się powtarzać.

Zobacz także ten komentarz, aby uzyskać więcej informacji na temat tego, dlaczego zwalnianie pamięci tuż przed zakończeniem jest złe.

Komentator wydawał się nie rozumieć, że wywołanie free()nie pozwala automatycznie innym programom na korzystanie z uwolnionej pamięci. Ale o to chodzi w tej odpowiedzi!

Tak więc, aby przekonać ludzi, pokażę przykład, w którym free () robi niewiele dobrego. Aby matematyka była łatwa do naśladowania, będę udawać, że system operacyjny zarządza pamięcią na 4000 bajtowych stronach.

Załóżmy, że alokujesz dziesięć tysięcy 100-bajtowych bloków (dla uproszczenia zignoruję dodatkową pamięć, która byłaby wymagana do zarządzania tymi alokacjami). To zużywa 1 MB lub 250 stron. Jeśli następnie uwolnisz 9000 tych bloków losowo, pozostanie tylko 1000 bloków - ale są one rozproszone po całym miejscu. Statystycznie około 5 stron będzie pustych. Pozostałe 245 będą miały co najmniej jeden przydzielony blok. Daje to 980 KB pamięci, której system operacyjny nie może odzyskać - mimo że teraz masz przydzielone tylko 100 KB!

Z drugiej strony, możesz teraz malloc () 9000 kolejnych bloków bez zwiększania ilości pamięci, którą program wiąże.

Nawet jeśli techniczniefree() może zwrócić pamięć do systemu operacyjnego, może tego nie zrobić. musi osiągnąć równowagę między szybkim działaniem a oszczędnością pamięci. Poza tym program, który już przydzielił dużo pamięci, a następnie zwolnił, prawdopodobnie zrobi to ponownie. Serwer WWW musi obsłużyć żądanie za żądaniem po żądaniu - sensowne jest utrzymywanie dostępnej „luźnej” pamięci, aby nie trzeba było cały czas pytać systemu operacyjnego o pamięć.free()

rev Artelius
źródło
1
Co jeśli inne programy wymagają pamięci, którą Twój program niepotrzebnie przetrzymuje, dlatego nawet jeśli nie potrzebujesz więcej malloców, zwolnij () nieużywane miejsca w pamięci :)
MN
2
Całkowicie przegapiłeś mój punkt. Gdy zwolnisz () pamięć, inne programy nie będą mogły jej używać !! (Czasami mogą, szczególnie jeśli zwalniasz duże bloki pamięci. Ale często nie mogą!) Zredaguję mój post, aby to wyjaśnić.
Artelius
27

Nie ma nic koncepcyjnie złego w czyszczeniu systemu operacyjnego po uruchomieniu aplikacji.

To zależy od aplikacji i sposobu jej uruchomienia. Należy dbać o stale występujące wycieki w aplikacji, która musi działać przez kilka tygodni, ale małe narzędzie, które oblicza wynik bez zbyt dużej pamięci, nie powinno stanowić problemu.

Istnieje powód, dla którego wiele języków skryptowych nie śmieci cyklicznych odwołań… ze względu na wzorce użycia nie jest to rzeczywisty problem, a zatem marnowanie zasobów byłoby tak samo marnotrawstwem pamięci.

kasperjj
źródło
Informacje o językach skryptowych: Python używa przeliczania, ale ma GC tylko po to, by uwolnić cykliczne odwołania. W innych językach programista często unika całkowicie cyklicznych odwołań, co stwarza inne problemy.
Blaisorblade,
Wcześniejsze wersje PHP nie zwalniały pamięci, po prostu działały od początku do końca, powiększając się w pamięci - po upływie zazwyczaj 0,1 sekundy czasu wykonania skrypt zakończył pracę i cała pamięć została odzyskana.
Arafangion
19

Uważam, że odpowiedź brzmi „nie”, nigdy nie dopuść do wycieku pamięci, i mam kilka powodów, których nie widziałem wyraźnie wyrażonych. Są tutaj świetne odpowiedzi techniczne, ale myślę, że prawdziwa odpowiedź zależy od bardziej społecznych / ludzkich powodów.

(Po pierwsze, zauważ, że jak wspomniano inni, prawdziwy wyciek ma miejsce, gdy twój program w dowolnym momencie traci ślad przydzielonych zasobów pamięci. W C dzieje się tak, gdy malloc()wskaźnik do wskaźnika pozwala na opuszczenie zakresu bez wykonywania polecenia free()pierwszy.)

Ważnym sednem twojej decyzji jest przyzwyczajenie. Kiedy piszesz w języku używającym wskaźników, będziesz często używać wskaźników . Wskaźniki są niebezpieczne; to najprostszy sposób na dodanie wszelkiego rodzaju poważnych problemów do kodu.

Kiedy kodujesz, czasami będziesz na piłce, a czasem będziesz zmęczony, wściekły lub zmartwiony. W tych nieco rozproszonych czasach kodujesz więcej na autopilocie. Efekt autopilota nie rozróżnia jednorazowego kodu od modułu w większym projekcie. W tych czasach nawyki, które ustanawiasz, znajdą się w twojej bazie kodu.

Więc nie, nigdy nie dopuszczaj do wycieków pamięci z tego samego powodu, dla którego powinieneś nadal sprawdzać martwe pola podczas zmiany pasów, nawet jeśli jesteś jedynym samochodem w tej chwili na drodze. W czasie, gdy twój aktywny mózg jest rozproszony, dobre nawyki są w stanie uratować cię przed katastrofalnymi błędami.

Oprócz kwestii „przyzwyczajenia” wskaźniki są złożone i często wymagają dużej mocy mózgu do śledzenia mentalnego. Najlepiej jest nie „moczyć wody”, jeśli chodzi o korzystanie ze wskaźników, szczególnie gdy dopiero zaczynasz programować.

Jest też aspekt społeczny. Dzięki właściwemu użyciu malloc()i free(), każdy, kto spojrzy na twój kod, będzie miał swobodę; zarządzasz swoimi zasobami. Jeśli tego nie zrobisz, natychmiast podejrzewają problem.

Być może zdałeś sobie sprawę, że wyciek pamięci niczego nie zaszkodzi w tym kontekście, ale każdy opiekun twojego kodu będzie musiał to sobie wyobrazić, gdy przeczyta ten fragment kodu. Korzystając z niej free(), usuniesz potrzebę nawet rozważenia problemu.

Wreszcie, programowanie pisze mentalny model procesu w jednoznacznym języku, aby osoba i komputer mogli doskonale zrozumieć ten proces. Istotną częścią dobrej praktyki programowania nigdy nie jest wprowadzanie niepotrzebnej dwuznaczności.

Inteligentne programowanie jest elastyczne i ogólne. Złe programowanie jest niejednoznaczne.

Jason L.
źródło
Uwielbiam ten nawyk. Również się zgadzam. Jeśli widzę wyciek pamięci, zawsze zastanawiam się, w którym innym rogu wyciął koder. Zwłaszcza jeśli to oczywiste
baash05
Jak dotąd najlepsza odpowiedź. Programuję w C ++ od 5 lat i nigdy nie napisałem ani jednego wycieku pamięci. Powodem jest to, że nie piszę kodu, który ma tendencję do wycieku pamięci. Dobry projekt C ++ rzadko się go stosuje new, dzięki czemu natychmiast eliminuje większość wycieków pamięci. Tylko jeśli absolutnie musisz tego użyć new. Wynik tego newnależy natychmiast umieścić w inteligentnym wskaźniku. Jeśli zastosujesz się do tych dwóch zasad, po prostu nigdy nie wyciekasz pamięci (z wyjątkiem błędu w bibliotece). Jedynym przypadkiem pozostały shared_ptrcykle, w takim przypadku musisz wiedzieć, aby użyć weak_ptr.
David Stone
15

Myślę, że w twojej sytuacji odpowiedź może być dobra. Ale zdecydowanie musisz udokumentować, że wyciek pamięci jest świadomą decyzją. Nie chcesz, aby pojawił się programista konserwacji, uderzył kod wewnątrz funkcji i wywołał go milion razy. Jeśli więc podejmiesz decyzję, że wyciek jest w porządku, musisz go udokumentować (DUŻYMI ​​LITERAMI) dla każdego, kto będzie musiał pracować nad programem w przyszłości.

Jeśli jest to biblioteka strony trzeciej, możesz zostać uwięziony. Ale zdecydowanie udokumentuj, że ten wyciek występuje.

Ale w zasadzie, jeśli wyciek pamięci jest znaną wielkością, taką jak bufor 512 KB lub coś takiego, to nie jest to problem. Jeśli wyciek pamięci rośnie, jak za każdym razem, gdy wywołujesz wywołanie biblioteczne, pamięć zwiększa się o 512 KB i nie jest zwalniana, możesz mieć problem. Jeśli go udokumentujesz i kontrolujesz liczbę wykonanych połączeń, możesz nim zarządzać. Ale wtedy naprawdę potrzebujesz dokumentacji, ponieważ choć 512 to niewiele, 512 ponad milion połączeń to dużo.

Musisz także sprawdzić dokumentację systemu operacyjnego. Jeśli było to urządzenie wbudowane, mogą istnieć systemy operacyjne, które nie zwalniają całej pamięci z zamykanego programu. Nie jestem pewien, może to nie jest prawda. Ale warto się temu przyjrzeć.

Cervo
źródło
3
„Ale zdecydowanie musisz udokumentować, że wyciek pamięci jest świadomą decyzją”. Dzięki Bogu. Jak dotąd najlepszy punkt.
pestofagiczny
15

Dam niepopularną, ale praktyczną odpowiedź, że zwalnianie pamięci zawsze jest złe, chyba że spowoduje to zmniejszenie zużycia pamięci przez program . Na przykład program, który dokonuje pojedynczej alokacji lub serii alokacji w celu załadowania zestawu danych, którego będzie używał przez cały okres istnienia, nie musi niczego zwalniać. W bardziej powszechnym przypadku dużego programu z bardzo dynamicznymi wymaganiami dotyczącymi pamięci (pomyśl o przeglądarce internetowej), powinieneś oczywiście zwolnić pamięć, której już nie używasz, tak szybko jak to możliwe (na przykład zamykając kartę / dokument / itp.) , ale nie ma powodu, aby cokolwiek zwalniać, gdy użytkownik wybierze kliknięcie „wyjdź”, a takie działanie jest w rzeczywistości szkodliwe dla wygody użytkownika.

Czemu? Zwolnienie pamięci wymaga dotknięcia pamięci. Nawet jeśli implementacja malloc w twoim systemie nie przechowuje metadanych w sąsiedztwie przydzielonych bloków pamięci, prawdopodobnie będziesz chodził strukturami rekurencyjnymi tylko po to, aby znaleźć wszystkie wskazówki, które musisz uwolnić.

Załóżmy teraz, że twój program działał z dużą ilością danych, ale od dłuższego czasu nie dotykał większości z nich (znowu przeglądarka internetowa jest świetnym przykładem). Jeśli użytkownik uruchamia wiele aplikacji, duża część tych danych prawdopodobnie została zamieniona na dysk. Jeśli po prostu wyjdziesz (0) lub wrócisz z głównego, wyjście natychmiast. Świetne wrażenia użytkownika. Jeśli próbujesz uwolnić wszystko, możesz poświęcić 5 sekund lub więcej na zamianę wszystkich danych z powrotem, tylko po to, aby natychmiast je wyrzucić. Strata czasu użytkownika. Marnowanie czasu pracy baterii laptopa. Odpady zużycia na dysku twardym.

To nie tylko teoretyczne. Ilekroć znajduję się z załadowaną zbyt dużą liczbą aplikacji, a dysk zaczyna się bić, nawet nie zastanawiam się nad kliknięciem „zamknij”. Dojeżdżam do terminala tak szybko, jak to możliwe i wpisuję killall -9 ... ponieważ wiem, że „wyjście” tylko pogorszy sytuację.

R .. GitHub ZATRZYMAJ LOD
źródło
5
Uwielbiam ten cytat Raymonda Chena: „Budynek jest wyburzony. Nie zawracaj sobie głowy zamiataniem podłogi, opróżnianiem pojemników na śmieci i wymazywaniem białych tablic. I nie ustawiaj się przy wyjściu do budynku, aby wszyscy mogli przenieść się do środka / od magnesu na zewnątrz. Wszystko, co robisz, to zmuszanie zespołu rozbiórkowego do czekania, aż zakończysz te bezcelowe zadania związane z czyszczeniem domu. ” ( blogs.msdn.microsoft.com/oldnewthing/20120105-00/?p=8683 )
Andreas Magnusson
11

Jestem pewien, że ktoś może wymyślić powód, aby powiedzieć Tak, ale to nie będę ja. Zamiast powiedzieć nie, powiem, że to nie powinno być pytanie tak / nie. Istnieją sposoby zarządzania lub ograniczania wycieków pamięci, a wiele systemów ma je.

Istnieją systemy NASA na urządzeniach, które opuszczają Ziemię, które to planują. Systemy będą automatycznie uruchamiać się ponownie tak często, aby przecieki pamięci nie były śmiertelne dla całej operacji. Tylko przykład ograniczania.

pearcewg
źródło
To właściwie przykład starzenia się oprogramowania. Fascynujący przedmiot studiów.
Konrad Rudolph
Automatyczny restart co jakiś czas, co? NASA, co? (* patrzy na stare instalacyjne dyski CD z systemem Microsoft Windows *) To wyjaśnia tyle ...
Christian Severin
8

Jeśli przydzielisz pamięć i wykorzystasz ją do ostatniej linii programu, nie będzie to przeciek. Jeśli przydzielisz pamięć i zapomnisz o niej, nawet jeśli ilość pamięci nie rośnie, to jest problem. Ta przydzielona, ​​ale nieużywana pamięć może powodować spowolnienie działania innych programów lub ich wcale.

Bill jaszczurka
źródło
Nie bardzo, ponieważ jeśli nie będzie używany, zostanie po prostu podzielony na strony. Po zamknięciu aplikacji cała pamięć jest zwalniana.
Eclipse
Dopóki jest przydzielony, inne programy nie będą mogły z niego korzystać. Nie zostanie on przywołany, jeśli go nie cofniesz.
Bill the Lizard
Oczywiście, że tak - na tym właśnie polega pamięć wirtualna. Możesz mieć 1 GB faktycznej pamięci RAM, a jednocześnie mieć 4 procesy, z których każdy w pełni przydziela 2 GB pamięci wirtualnej (o ile plik strony jest wystarczająco duży).
Zaćmienie
Oczywiście wystąpią nieprzyjemne problemy ze stronicowaniem, jeśli każdy z tych procesów aktywnie wykorzystuje całą tę pamięć.
Zaćmienie
OK, rozumiem o czym teraz mówisz. Jeśli zwolnisz pamięć, której nie używasz, zmniejszysz potrzebę stronicowania. Jeśli trzymać to przydzielone, aplikacja będzie nadal trzymać go, kiedy jest Paged widok.
Bill Lizard
8

Mogę liczyć z jednej strony liczbę „łagodnych” wycieków, które widziałem w czasie.

Tak więc odpowiedź jest bardzo wykwalifikowana tak.

Przykład. Jeśli masz zasób singletonu, który potrzebuje bufora do przechowywania kolejki cyklicznej lub deque, ale nie wie, jak duży będzie ten bufor, i nie może sobie pozwolić na obciążenie związane z blokowaniem lub każdym czytnikiem, wówczas alokuje się wykładniczo podwójny bufor, ale nie zwolnienie starych spowoduje wyciek ograniczonej ilości pamięci na kolejkę / deque. Ich zaletą jest to, że znacznie przyspieszają każdy dostęp i mogą zmienić asymptotykę rozwiązań wieloprocesorowych, nigdy nie ryzykując rywalizacji o zamek.

Zauważyłem, że takie podejście przyniosło wiele korzyści w przypadku rzeczy o bardzo wyraźnie ustalonych liczbach, takich jak deques kradnące pracę na procesor, oraz w znacznie mniejszym stopniu w buforze używanym do przechowywania singletonu /proc/self/maps stanu w konserwatywnym śmieciarzu Hansa Boehm'a dla C / C ++, który służy do wykrywania zestawów głównych itp.

Chociaż technicznie jest to wyciek, oba te przypadki są ograniczone pod względem wielkości, aw rosnącej krętej pracy kradnącej skrzynkę deque istnieje ogromna wygrana wydajności w zamian za czynnik związany z 2 wzrostem wykorzystania pamięci dla kolejek.

Edward KMETT
źródło
1
Możesz użyć wskaźników zagrożenia, aby zapobiec wyciekom.
Demi
8

Jeśli na początku programu przydzielisz sporo sterty i nie zwolnisz go po wyjściu, nie będzie to samo w sobie wycieku pamięci. Wyciek pamięci występuje, gdy program zapętla sekcję kodu, a ten kod przydziela stertę, a następnie „traci ją” bez zwalniania.

W rzeczywistości nie ma potrzeby wykonywania połączeń z free () lub usuwania bezpośrednio przed wyjściem. Kiedy proces kończy się, cała jego pamięć jest odzyskiwana przez system operacyjny (z pewnością ma to miejsce w przypadku POSIX. W innych systemach operacyjnych - szczególnie osadzonych - YMMV).

Jedyną ostrożnością, którą chciałbym zachować, aby nie zwolnić pamięci w momencie wyjścia, jest to, że jeśli kiedykolwiek zmienisz program tak, aby na przykład stał się usługą, która czeka na dane wejściowe, robi wszystko, co robi program, a następnie zapętla się, czekając na kolejne zgłoszenie serwisowe, a następnie to, co zakodowałeś, może zmienić się w wyciek pamięci.

nsayer
źródło
Pozwolę sobie być innego zdania. Że jest „pamięć przeciek per se”.
Konrad Rudolph
To nie jest wyciek, dopóki „nie zgubisz” odniesienia do obiektu. Przypuszczalnie, jeśli pamięć jest używana przez cały czas trwania programu, to nie wycieknie. Jeśli odwołanie nie zostanie utracone, dopóki nie zostanie wywołane exit (), to absolutnie nie jest to przeciek.
nsayer
Amiga DOS był ostatnim spojrzeniem O / SI, które nie oczyściło procesów. Pamiętaj jednak, że pamięć współdzieloną IPC Systemu V można pozostawić, nawet jeśli żaden proces jej nie używa.
Jonathan Leffler,
Palm nie zwalnia pamięci, dopóki „nie wyciekłeś”. przyszło dobrze po Amiga. Na emulatorze dłoni uruchomiłem aplikacje, które miały przecieki. Nigdy nie dotarły do ​​mojej dłoni.
baash05
6

jest to tak specyficzne dla domeny, że nie warto na nie odpowiadać. użyj swojej cholernej głowy.

  • system operacyjny promu kosmicznego: nie, niedozwolone są wycieki pamięci
  • kod „proof-of-concept” szybkiego rozwoju: usunięcie wszystkich wycieków pamięci to strata czasu.

i istnieje szereg sytuacji pośrednich.

koszt alternatywny ($$$) opóźnienia wydania produktu w celu naprawienia wszystkich oprócz najgorszych wycieków pamięci zwykle przyćmiewa wszelkie poczucie bycia „niechlujnym lub nieprofesjonalnym”. Twój szef płaci ci za zarabianie pieniędzy, a nie za ciepłe, niewyraźne uczucia.

Dustin Getz
źródło
2
Postawa krótkowzroczna. Mówisz w zasadzie, że nie ma potrzeby stosowania zasadniczo solidnych praktyk programowania, dopóki nie zostanie stwierdzona wada spowodowana przez te praktyki. Problem polega na tym, że oprogramowanie napisane przy użyciu niechlujnych metod ma zwykle więcej wad niż oprogramowanie, które nie jest.
John Dibling,
1
Nie wierzę w to wszystko. A zarządzanie pamięcią jest bardziej skomplikowane niż pisanie czystych metod.
Dustin Getz
1
Dustin oczywiście działa w prawdziwym świecie, jak większość z nas, gdzie nieustannie pracujemy wbrew szalonym terminom, aby dotrzymać kroku konkurencji. Dlatego radzenie sobie z błędami powinno odbywać się w sposób pragmatyczny. Marnując zbyt wiele czasu na nieistotne błędy w nieistotnych programach, nie załatwisz swoich spraw.
Wouter van Nifterick
Problem z tym podejściem jest następujący: kiedy zaczynasz naprawiać przecieki? „OK, to elektrownia, ale to tylko węgiel, a nie uran. Po co naprawiać przecieki tutaj?” - Nauczyłem się w prawdziwym świecie, że jeśli od samego początku nie postępujesz właściwie, to po prostu tak się nigdy nie dzieje. Takie podejście rodzi projekty, które są „ukończone w 99%” po dwóch tygodniach i pozostają takie przez dwa miesiące.
peterchen
5

Musisz najpierw uświadomić sobie, że istnieje duża różnica między postrzeganym wyciekiem pamięci a rzeczywistym wyciekiem pamięci. Bardzo często narzędzia analityczne zgłaszają wiele czerwonych śledzi i opisują coś jako wyciek (pamięć lub zasoby, takie jak uchwyty itp.) Tam, gdzie tak naprawdę nie jest. Często wynika to z architektury narzędzia analizy. Na przykład niektóre narzędzia analityczne zgłaszają obiekty wykonawcze jako wycieki pamięci, ponieważ nigdy nie widzą uwolnienia tych obiektów. Ale zwolnienie następuje w kodzie zamykania środowiska wykonawczego, którego narzędzie analizy może nie widzieć.

Powiedziawszy to, nadal będą chwile, w których rzeczywiste wycieki pamięci będą albo bardzo trudne do znalezienia, albo bardzo trudne do naprawienia. Teraz pojawia się pytanie, czy pozostawienie ich w kodzie jest w porządku?

Idealna odpowiedź brzmi: „nie, nigdy”. Bardziej pragmatyczną odpowiedzią może być „nie, prawie nigdy”. Bardzo często w prawdziwym życiu masz ograniczoną liczbę zasobów i czasu do rozwiązania oraz nieskończoną listę zadań. Kiedy jednym z zadań jest eliminowanie wycieków pamięci, bardzo często pojawia się zasada malejących zwrotów. Można wyeliminować np. 98% wszystkich wycieków pamięci w aplikacji w ciągu tygodnia, ale pozostałe 2% może potrwać miesiące. W niektórych przypadkach wyeliminowanie pewnych przecieków może być niemożliwe ze względu na architekturę aplikacji bez znacznej zmiany kodu. Musisz rozważyć koszty i korzyści wynikające z wyeliminowania pozostałych 2%.

John Dibling
źródło
5

W tego rodzaju pytaniach kontekst jest wszystkim. Osobiście nie mogę znieść przecieków, aw swoim kodzie staram się je naprawić, jeśli się pojawią, ale nie zawsze warto naprawić wyciek, a kiedy ludzie płacą mi za godzinę, mam czasem powiedziałem im, że nie warto płacić za naprawienie wycieku w kodzie. Dam ci przykład:

Pracowałem nad projektem, wykonałem perfekcyjną pracę i naprawiłem wiele błędów. Podczas inicjacji aplikacji wystąpił wyciek, który wyśledziłem i w pełni zrozumiałem. Prawidłowe jego naprawienie wymagałoby około dnia refaktoryzacji fragmentu funkcjonalnego kodu. Mógłbym zrobić coś hackującego (np. Wpychanie wartości do globalnej i chwytanie jej w pewnym momencie, wiem, że nie było już używane do uwolnienia), ale to spowodowałoby więcej zamieszania u następnego faceta, który musiał dotknąć kodu.

Osobiście nie napisałbym kodu w ten sposób, ale większość z nas nie zawsze musi pracować nad nieskazitelnie dobrze zaprojektowanymi bazami kodów, a czasami trzeba patrzeć na te rzeczy pragmatycznie. Czas, który zajęłoby mi naprawienie tego, że wyciek 150 bajtów mógłby zamiast tego zostać wykorzystany na ulepszenia algorytmu, które zmniejszyłyby megabajty pamięci RAM.

Ostatecznie zdecydowałem, że wyciek 150 bajtów dla aplikacji, która używała około gigabajta pamięci RAM i działał na dedykowanej maszynie, nie był wart naprawy, więc napisałem komentarz, że wyciekł, co należy zmienić, aby naprawić i dlaczego nie było warto w tym czasie.

Louis Gerbarg
źródło
Mądry. Zwłaszcza, że ​​przeciek nastąpił podczas inicjalizacji, co oznacza, że ​​nie gromadziłby się on w czasie działania aplikacji.
Demi
5

Podczas gdy większość odpowiedzi koncentruje się na prawdziwych przeciekach pamięci (które nigdy nie są OK, ponieważ są oznaką niechlujnego kodowania), ta część pytania wydaje mi się bardziej interesująca:

Co się stanie, jeśli przydzielisz trochę pamięci i wykorzystasz ją do ostatniego wiersza kodu w aplikacji (na przykład dekonstruktora obiektu globalnego)? O ile zużycie pamięci nie rośnie z czasem, czy można ufać systemowi operacyjnemu, który zwolni twoją pamięć po zakończeniu aplikacji (w systemach Windows, Mac i Linux)? Czy uznałbyś to za prawdziwy wyciek pamięci, gdyby pamięć była używana nieprzerwanie, dopóki nie zostanie zwolniona przez system operacyjny.

Jeśli używana jest powiązana pamięć, nie można jej zwolnić przed zakończeniem programu. To, czy uwolnienie odbywa się przez wyjście z programu, czy przez system operacyjny, nie ma znaczenia. Tak długo, jak jest to udokumentowane, aby zmiana nie powodowała prawdziwych wycieków pamięci, i dopóki w obrazie nie występuje żadna funkcja C ++ destructor lub funkcja czyszczenia C. Niezamknięty plik może zostać ujawniony przez wyciekający FILEobiekt, ale brakująca funkcja fclose () może również spowodować, że bufor nie zostanie opróżniony.

Tak więc, wracając do oryginalnej skrzynki, samo w sobie jest całkowicie OK IMHO, tak bardzo, że Valgrind, jeden z najsilniejszych wykrywaczy wycieków, leczy takie wycieki tylko na żądanie. W przypadku Valgrind, gdy nadpisujesz wskaźnik bez wcześniejszego jego zwolnienia, jest on uważany za wyciek pamięci, ponieważ jest bardziej prawdopodobne, że powtórzy się i spowoduje nieskończony wzrost stosu.

Następnie nie ma dostępnych bloków pamięci, które są nadal dostępne. Można się upewnić, że wszystkie zostaną uwolnione przy wyjściu, ale to tylko strata czasu sama w sobie. Chodzi o to, czy mogliby być wcześniej uwolnieni . W każdym przypadku przydatne jest zmniejszenie zużycia pamięci.

Blaisorblade
źródło
Wow ... ktoś, kto wie, co to jest wyciek pamięci.
Simon Buchan
4

Zgadzam się z vfilby - to zależy. W Windows traktujemy wycieki pamięci jako stosunkowo poważne błędy. Ale to bardzo zależy od komponentu.

Na przykład wycieki pamięci nie są bardzo poważne w przypadku komponentów, które działają rzadko i przez ograniczony czas. Te komponenty działają, wykonują pracę, a następnie wychodzą. Kiedy wychodzą, cała pamięć zostaje uwolniona niejawnie.

Jednak wycieki pamięci w usługach lub innych komponentach długo działających (takich jak powłoka) są bardzo poważne. Powodem jest to, że te błędy „kradną” pamięć z czasem. Jedynym sposobem na odzyskanie tego jest ponowne uruchomienie komponentów. Większość ludzi nie wie, jak zrestartować usługę lub powłokę - więc jeśli spadnie wydajność ich systemu, po prostu uruchomią się ponownie.

Więc jeśli masz wyciek - oceń jego wpływ na dwa sposoby

  1. Do Twojego oprogramowania i wrażeń użytkownika.
  2. Do systemu (i użytkownika) pod względem oszczędności zasobów systemowych.
  3. Wpływ poprawki na konserwację i niezawodność.
  4. Prawdopodobieństwo spowodowania regresji w innym miejscu.

Foredecker

Foredecker
źródło
3. Wpływ na konserwację oprogramowania.
peterchen
3

Nawet jeśli masz pewność, że „znany” wyciek pamięci nie spowoduje spustoszenia, nie rób tego. W najlepszym razie utoruje ci drogę do popełnienia podobnej i prawdopodobnie bardziej krytycznej pomyłki w innym czasie i miejscu.

Dla mnie zadawanie tego jest jak pytanie: „Czy mogę rozbić czerwone światło o 3 nad ranem, kiedy nikogo nie ma w pobliżu?”. Oczywiście nie może to powodować żadnych problemów, ale zapewni ci dźwignię, abyś zrobił to samo w godzinach szczytu!

Ather
źródło
3

Nie, nie powinieneś mieć przecieków, które system operacyjny wyczyści dla Ciebie. Powodem (o którym nie wspomniano w odpowiedziach powyżej, o ile mogłem to sprawdzić) jest to, że nigdy nie wiesz, kiedy twoja funkcja main () zostanie ponownie użyta jako funkcja / moduł w innym programie . Jeśli twoja funkcja main () stanie się często wywoływaną funkcją w oprogramowaniu innej osoby - w tym oprogramowaniu wystąpi wyciek pamięci, który z czasem zjada pamięć.

KIV


źródło
3

Myślę, że to w porządku, jeśli piszesz program przeznaczony do wycieku pamięci (tj. Do testowania wpływu wycieków pamięci na wydajność systemu).

Sygnał dźwiękowy
źródło
3

Jestem zaskoczony, widząc tak wiele niepoprawnych definicji wycieku pamięci. Bez konkretnej definicji dyskusja na temat tego, czy jest to zła rzecz, czy nie, nic nie da.

Jak słusznie zauważyli niektórzy komentatorzy, wyciek pamięci występuje tylko wtedy, gdy pamięć przydzielona przez proces wykracza poza zakres w zakresie, w jakim proces nie jest już w stanie go odwoływać ani usuwać.

Proces, który chwyta coraz więcej pamięci niekoniecznie przecieka. Tak długo, jak jest w stanie odwoływać się do tej pamięci i ją zwalniać, pozostaje ona pod wyraźną kontrolą procesu i nie wyciekła. Proces ten może być źle zaprojektowany, szczególnie w kontekście systemu, w którym pamięć jest ograniczona, ale to nie to samo, co przeciek. I odwrotnie, utrata zakresu, powiedzmy, 32-bajtowego bufora jest nadal przeciekaniem, nawet jeśli ilość wycieku pamięci jest niewielka. Jeśli uważasz, że jest to nieistotne, poczekaj, aż ktoś obejmie algorytm wokół twojego wywołania w bibliotece i zadzwoni do niego 10 000 razy.

Nie widzę powodu, aby zezwalać na wycieki w twoim własnym kodzie, nawet najmniejszym. Współczesne języki programowania, takie jak C i C ++, bardzo się starają, aby pomóc programistom zapobiegać takim wyciekom, a rzadko jest dobry argument, aby nie stosować dobrych technik programowania - szczególnie w połączeniu z określonymi udogodnieniami językowymi - aby zapobiec wyciekom.

W odniesieniu do istniejącego kodu lub kodu strony trzeciej, gdzie kontrola nad jakością lub zdolność do zmiany może być bardzo ograniczona, w zależności od powagi wycieku, możesz zostać zmuszony do zaakceptowania lub podjęcia działań łagodzących, takich jak regularne ponowne uruchamianie procesu w celu ograniczenia efekt wycieku.

Zmiana lub wymiana istniejącego (nieszczelnego) kodu może być niemożliwa, dlatego możesz zostać zobowiązany do jego zaakceptowania. Nie jest to jednak to samo, co deklarowanie, że jest OK.

Komponent 10
źródło
2

To naprawdę nie jest wyciek, jeśli jest celowy i nie stanowi problemu, chyba że ma znaczną ilość pamięci lub może wzrosnąć do znacznej ilości pamięci. Dość powszechne jest to, że nie usuwają globalnych przydziałów w trakcie trwania programu. Jeśli wyciek występuje w serwerze lub długo działającej aplikacji, rośnie z czasem, to jest problem.

Sanjaya R.
źródło
2

Myślę, że odpowiedziałeś na własne pytanie. Największą wadą jest to, że kolidują one z narzędziami do wykrywania wycieków pamięci, ale myślę, że wadą jest OGROMNA wada dla niektórych rodzajów aplikacji.

Pracuję ze starszymi aplikacjami serwerowymi, które powinny być solidne, ale mają przecieki, a globale przeszkadzają w wykrywaniu pamięci. To ważna sprawa.

W książce „Upadek” Jareda Diamonda autor zastanawia się, o czym myślał facet, który ściął ostatnie drzewo na Wyspie Wielkanocnej, drzewo, którego potrzebowałby, aby zbudować kajak, aby wydostać się z wyspy. Zastanawiam się, jak wiele lat temu ten pierwszy globalny został dodany do naszej bazy kodów. Tego dnia powinien był zostać złapany.

Corey Trager
źródło
2

Widzę ten sam problem, co wszystkie takie pytania scenariusza: Co dzieje się, gdy program się zmienia i nagle ten mały wyciek pamięci jest wywoływany dziesięć milionów razy, a koniec twojego programu jest w innym miejscu, więc to ma znaczenie? Jeśli jest w bibliotece, zaloguj się do opiekuna biblioteki, nie wyciekaj do własnego kodu.

tloach
źródło
W takim przypadku zmienia się wpływ wycieku pamięci i należy ponownie ocenić priorytet wycieku pamięci.
John Dibling,
@John: Lepiej przynajmniej udokumentuj wyciek. Nawet wtedy nie ufałbym komuś, że nie zignoruje dużego czerwonego migającego komentarza i skopiuje i wklei nieszczelny kod. Wolę nie dać komuś możliwości zrobienia tego w pierwszej kolejności.
tloach
2

Odpowiem nie.

Teoretycznie system operacyjny posprząta po tobie, jeśli zostawisz bałagan (teraz jest to po prostu niegrzeczne, ale ponieważ komputery nie mają uczuć, może to być dopuszczalne). Ale nie można przewidzieć każdej możliwej sytuacji, która może wystąpić podczas uruchamiania programu. Dlatego (chyba że jesteś w stanie przeprowadzić formalny dowód niektórych zachowań), tworzenie wycieków pamięci jest po prostu nieodpowiedzialne i niechlujne z profesjonalnego punktu widzenia.

Jeśli komponent innej firmy wycieka z pamięci, jest to bardzo silny argument przeciwko jej użyciu, nie tylko z powodu bezpośredniego efektu, ale także dlatego, że pokazuje, że programiści działają niechętnie i że może to również wpływać na inne parametry. Teraz, gdy rozważamy starsze systemy, jest to trudne (rozważ komponenty do przeglądania stron internetowych: według mojej wiedzy wszystkie one przeciekają pamięć), ale powinna to być norma.

Konrad Rudolph
źródło
2

Historycznie miało to znaczenie w niektórych systemach operacyjnych w niektórych przypadkach skrajnych. Te przypadki skrajne mogą istnieć w przyszłości.

Oto przykład: w systemie SunOS w erze Sun 3 wystąpił problem, jeśli proces używał exec (lub bardziej tradycyjnie rozwidla, a następnie exec), późniejszy nowy proces odziedziczyłby taki sam ślad pamięci jak rodzic i nie mógł zostać skurczony . Jeśli proces nadrzędny przydzieli 1/2 gigabajta pamięci i nie zwolni go przed wywołaniem exec, proces potomny zacznie używać tej samej 1/2 gigabajta (nawet jeśli nie został przydzielony). To zachowanie najlepiej pokazał SunTools (ich domyślny system okienkowy), który był świnią pamięci. Każda aplikacja, którą stworzyła, została utworzona za pomocą fork / exec i odziedziczyła ślad SunTools, szybko wypełniając przestrzeń wymiany.

cokół
źródło
2

Zostało to już omówione ad nauseam . Najważniejsze jest to, że wyciek pamięci jest błędem i musi zostać naprawiony. Jeśli biblioteka innej firmy wycieka z pamięci, to zastanawia się, co jeszcze jest z nią nie tak, nie? Gdybyś budował samochód, czy użyłbyś silnika, który czasami wycieka olej? W końcu ktoś zrobił silnik, więc to nie twoja wina i nie możesz tego naprawić, prawda?

Dima
źródło
Ale jeśli posiadasz samochód z silnikiem, który od czasu do czasu wycieka olej, wydajesz pieniądze na jego naprawę, czy pilnujesz poziomu oleju i od czasu do czasu go uzupełniasz. Odpowiedź zależy od wszystkich czynników.
szczupły
Tu nie chodzi o posiadanie samochodu. Chodzi o zbudowanie samochodu. Jeśli otrzymujesz bibliotekę innej firmy z wyciekami pamięci i absolutnie musisz jej użyć, to musisz z nią żyć. Ale jeśli piszesz system lub bibliotekę, Twoim obowiązkiem jest upewnić się, że nie zawiera błędów.
Dima,
+1 traktuj to jak każdy inny błąd. (To nie znaczy „napraw natychmiast” w mojej książce, ale „na pewno musi zostać poprawiony”)
peterchen
2

Zasadniczo wyciek pamięci w samodzielnej aplikacji nie jest śmiertelny, ponieważ jest usuwany po wyjściu z programu.

Co robisz dla programów serwera zaprojektowanych tak, aby się nie zamykały?

Jeśli jesteś programistą, który nie projektuje i nie implementuje kodu, w którym zasoby są przydzielane i zwalniane poprawnie, nie chcę mieć nic wspólnego z tobą ani twoim kodem. Jeśli nie chcesz wyczyścić wyciekającej pamięci, co z twoimi zamkami? Czy zostawiasz je tam również? Czy zostawiasz małe pliki tymczasowych plików leżące w różnych katalogach?

Wyciekła pamięć i pozwolił programowi ją wyczyścić? Nie, absolutnie nie. To zły nawyk, który prowadzi do błędów, błędów i innych błędów.

Posprzątaj po sobie. Wasza mamo, już tu nie pracuje.

EvilTeach
źródło
Pracowałem nad programami serwerowymi, które celowo wykorzystują procesy, a nie wątki, aby wycieki pamięci i błędy segmentacji powodowały ograniczone uszkodzenia.
szczupły
Ciekawe podejście Byłbym trochę zaniepokojony procesami, które nie wychodzą i nadal pochłaniają pamięć.
EvilTeach,
2

Zasadniczo, jeśli masz wycieki pamięci, których nie możesz uniknąć, musisz się bardziej zastanowić nad własnością obiektu.

Ale na twoje pytanie moja odpowiedź w skrócie brzmi: W kodzie produkcyjnym, tak. Podczas rozwoju nie . Może się to wydawać wstecz, ale oto moje rozumowanie:

W opisywanej sytuacji, w której pamięć jest przechowywana do końca programu, nie można jej zwolnić. Po zakończeniu procesu system operacyjny i tak wyczyści system. W rzeczywistości może to poprawić wrażenia użytkownika: w grze, nad którą pracowałem, programiści sądzili, że zwolnienie całej pamięci przed wyjściem byłoby czystsze, powodując zamknięcie programu nawet do pół minuty! Szybka zmiana, która właśnie wywołała exit (), sprawiła, że ​​proces natychmiast zniknął, i umieścił użytkownika z powrotem na pulpicie, gdzie chciał być.

Jednak masz rację co do narzędzi do debugowania: sprawdzą się, a wszystkie fałszywe alarmy mogą sprawić, że znalezienie prawdziwej pamięci wycieka z bólu. Z tego powodu zawsze pisz kod debugujący, który zwalnia pamięć, i wyłączaj ją podczas wysyłania.

Enno
źródło