2014-06-15 12 views
6

Słyszałem wiele razy, że gdy program zarządzany w C# zażądał więcej pamięci od systemu operacyjnego, nie zwalnia go, chyba że systemowi brakuje pamięci. Na przykład. gdy obiekt jest zbierany, zostaje usunięty, a pamięć zajmowana przez obiekt może zostać ponownie wykorzystana przez inny obiekt zarządzany, ale sama pamięć nie jest zwracana do systemu operacyjnego (na przykład mono na systemie UNIX nie wywołuje nazwy brk/sbrk zmniejszyć ilość pamięci wirtualnej dostępnej dla procesu z powrotem do tego, co było przed jej przydzieleniem).czy mono/.Net GC zwalnia wolną przydzieloną pamięć z powrotem do systemu operacyjnego po pobraniu? jeśli nie, dlaczego?

Nie wiem, czy to naprawdę się dzieje, czy nie, ale widzę, że moje aplikacje C#, działające na Linuksie, używają małej ilości pamięci na początku, a kiedy robię coś drogiego, to przydzielają więcej , ale później, gdy wszystkie obiekty zostaną usunięte (mogę to zweryfikować, umieszczając komunikat debugowania w destruktorze), pamięć nie jest wolna. Z drugiej strony, po ponownym uruchomieniu tej kosztownej operacji pamięci nie jest już przydzielana żadna pamięć. Program po prostu kontynuuje spożywanie tej samej ilości pamięci, aż do jej zakończenia.

Może to tylko moje niezrozumienie, jak GC w .net działa, ale jeśli to naprawdę działa, dlaczego tak jest? Co to jest korzyść z utrzymywania przydzielonej pamięci na później, zamiast zwracania jej z powrotem do systemu? Jak może nawet wiedzieć, czy system potrzebuje go z powrotem, czy nie? A co z inną aplikacją, która uległa awarii lub nie mogła się uruchomić z powodu OOM spowodowanej przez ten efekt?

Wiem, że ludzie prawdopodobnie odpowiedzą na coś w rodzaju: "GC zarządza pamięcią lepiej niż kiedykolwiek, po prostu nie przejmuj się tym" lub "GC wie, co robi najlepiej" lub "to w ogóle nie ma znaczenia, to tylko wirtualna pamięć ", ale to ma znaczenie, na moim laptopie 2GB korzystam z OOM (i z tego powodu uruchamiany jest OOM z kernela) bardzo często, gdy po jakimś czasie uruchamiam aplikacje C# właśnie z powodu nieodpowiedzialnego zarządzania pamięcią.

Uwaga: Testowałem to wszystko na mono w Linuksie, ponieważ naprawdę ciężko mi zrozumieć, jak okna zarządzają pamięcią, więc debugowanie na Linuksie jest dla mnie o wiele łatwiejsze, także zarządzanie pamięcią linuksową to open source code, zarządzanie pamięcią okien kernel/.Net jest dla mnie dość tajemniczy.

+0

Nie jestem odpowiedzią, ale polecam wyszukać artykuły/filmy z [Maoni Stephens] (http://channel9.msdn.com/posts/Maoni-Stephens-CLR-45-Server-Background-GC). Jest deweloperem GC Lead ... – rene

+3

To jest bardzo specyficzny problem z Linuksem, masz to, o co prosiłeś. Po prostu [wyłącz to] (http://jurjenbokma.com/ApprenticesNotes/turing_off_overcommit.html). –

Odpowiedz

4

Menedżer pamięci działa w ten sposób, ponieważ nie ma korzyści z posiadania dużej ilości nieużywanej pamięci systemowej, kiedy jej nie potrzebujesz.

Jeśli menedżer pamięci zawsze starał się mieć jak najmniej przydzielonej pamięci, oznaczałoby to, że wykonałoby to wiele pracy bez powodu. Zmniejszyłoby to działanie aplikacji, a jedyną korzyścią byłaby większa ilość wolnej pamięci, której nie używa żadna aplikacja.

Gdy system potrzebuje więcej pamięci, informuje uruchomione aplikacje, aby zwracały jak najwięcej. Ten sam sygnał jest również wysyłany do aplikacji, gdy ją zminimalizujesz.

Jeśli to nie działa tak samo z Mono w Linuksie, to jest problem z tą konkretną implementacją.

+0

Pierwsza linia wydaje się sprzeczna z resztą ...? –

+0

@MarcGravell: W jaki sposób? – Guffa

+0

Ach, myślę, że widzę: Czytałem pierwszą linię jako "w twoim procesie" - czyli odnosząc się do menedżera pamięci. Jeśli masz na myśli "w twoim systemie", to: świetnie –

3

Zasadniczo, jeśli aplikacja potrzebuje pamięci raz, będzie potrzebna ponownie. Zwolnienie pamięci z powrotem do systemu operacyjnego tylko po to, aby zażądać jej zwrotu, jest napowietrzne, a jeśli nic więcej nie chce pamięci: po co?. Stara się zoptymalizować pod kątem bardzo prawdopodobnego scenariusza, jeśli chce go ponownie. Dodatkowo, zwolnienie go z powrotem wymaga całych/ciągłych bloków, które można przekazać z powrotem, co ma bardzo szczególny wpływ na rzeczy takie jak zagęszczanie: nie jest tak proste, jak "hej, nie używam większości tego: mam to z powrotem" - musi ustalić, które bloki mogą zostać zwolnione, prawdopodobnie po pełnym zbiorze i zwarciu (przemieścić obiekty itp.).

+0

czy jesteś pewien, że gdy aplikacja potrzebuje pamięci, będzie jej potrzebować ponownie? co się stanie, jeśli otworzę 30 kart w przeglądarce, a następnie zdecyduję o zamknięciu 20 z nich, aby zwolnić trochę pamięci, aby móc uruchomić inny program, który będzie go potrzebować. Gdyby pamięć nie została zwrócona do systemu, musiałbym zakończyć całą aplikację za każdym razem (co muszę teraz zrobić). – Petr

+0

@Petr, który zależy od sposobu zaimplementowania przeglądarki; w przypadku chrome: proces na zakładkę –

Powiązane problemy