Czym dokładnie są niezarządzane zasoby?

159

Chcę wiedzieć o niezarządzanych zasobach. Czy ktoś może mi podać podstawowy pomysł?

Deviprasad Das
źródło
Zobacz także tę stronę, która zawiera fantastyczne wyjaśnienie i wzór prawidłowego korzystania z IDisposable oraz sposobu uwzględniania niezarządzanych zasobów: stackoverflow.com/questions/538060/ ...
Kyle Baran

Odpowiedzi:

177

Zarządzane zasoby zasadniczo oznaczają „pamięć zarządzaną”, która jest zarządzana przez moduł odśmiecania pamięci. Gdy nie masz już żadnych odwołań do obiektu zarządzanego (który używa pamięci zarządzanej), moduł odśmiecania pamięci (ostatecznie) zwolni tę pamięć za Ciebie.

Zasoby niezarządzane są wtedy wszystkim, o czym garbage collector nie wie. Na przykład:

  • Otwórz pliki
  • Otwarte połączenia sieciowe
  • Pamięć niezarządzana
  • W XNA: bufory wierzchołków, bufory indeksów, tekstury itp.

Zwykle chcesz zwolnić te niezarządzane zasoby, zanim utracisz wszystkie posiadane odniesienia do obiektu, który nimi zarządza. Robisz to, wywołując Disposeten obiekt lub (w C #) używając usinginstrukcji, która będzie obsługiwać wywoływanie Disposeza Ciebie.

Jeśli Disposeprawidłowo zaniedbasz niezarządzane zasoby, moduł odśmiecania pamięci ostatecznie zajmie się tym za Ciebie, gdy obiekt zawierający ten zasób zostanie usunięty (jest to „finalizacja”). Ale ponieważ garbage collector nie wie o niezarządzanych zasobach, nie może stwierdzić, jak bardzo musi je zwolnić - więc możliwe jest, że Twój program będzie działał słabo lub całkowicie zabrakło zasobów.

Jeśli zaimplementować klasę sobie, że uchwyty niezarządzalny zasobów, to do ciebie, aby wdrożyć Disposei Finalizeprawidłowo.

Andrew Russell
źródło
7
Do której kategorii należy połączenie z otwartą bazą danych? Zarządzane / niezarządzane?
Deviprasad Das
8
+1 Inne odpowiedzi pomijają ważny punkt, który wywołujesz Dispose na zarządzanym obiekcie, który wewnętrznie obsługuje zwalnianie niezarządzanego zasobu, który opakowuje (np. Uchwyt pliku, GDI + bitmapa, ...), a jeśli masz bezpośredni dostęp do niezarządzanych zasobów ( PInvoke itp.), Musisz sobie z tym poradzić.
Ian Mercer
2
@Dev: Unmanaged - ponieważ GC o tym nie wie (zakładając, że nie używasz hipotetycznej bazy danych w pamięci zarządzanej). Ale sam obiekt połączenia może nie zawierać niezarządzanego zasobu. Przypuszczalnie połączenie z bazą danych wykorzystuje gdzieś otwarty plik lub połączenie sieciowe - ale możliwe jest , że inny obiekt (inny niż obiekt połączenia) obsługuje ten niezarządzany zasób (być może twoja biblioteka bazy danych przechowuje połączenia). Sprawdź dokumentację i zobacz, gdzie prosi Cię o telefon Disposelub użycie using.
Andrew Russell
11
Mam podstawowy komentarz / pytanie na ten temat, czy mogę powiązać obiekt jako zarządzany / niezarządzany tylko według typu, na przykład ciąg jest zarządzany, DataSet jest niezarządzany (dlatego ma metodę Dispose ()) , Połączenia z bazą danych są niezarządzane (ponieważ mają zlikwidowane) itp. Czy zatem założenie, że jeśli ma metodę „Dispose ()”, to jest niezarządzane? Oprócz tego, czym byłby obiekt XmlDocument? Dzięki
ganders
15
@ganders To dobra zasada. Należy jednak pamiętać, że wszystkie wystąpienia klas C # są obiektami zarządzanymi. Jeśli instancja klasy może zawierać niezarządzane zasoby, to ta klasa powinna być implementowana IDisposable. Jeśli klasa ma realizować IDisposable, to powinien dysponować instancji tej klasie usinglub Dispose()gdy jesteś z nimi zrobić. Opierając się na tym, twoja odwrotność utrzymuje się: jeśli klasa implementuje IDisposable, to prawdopodobnie wewnętrznie przechowuje niezarządzane zasoby.
Andrew Russell,
56

Niektórzy użytkownicy klasyfikują otwarte pliki, połączenia bazy danych, przydzieloną pamięć, mapy bitowe, strumienie plików itp. Wśród zarządzanych zasobów, inni jako niezarządzane. Więc są zarządzane czy niezarządzane?

Moim zdaniem odpowiedź jest bardziej złożona: Kiedy otwierasz plik w .NET, prawdopodobnie używasz jakiejś wbudowanej klasy .NET System.IO.File, FileStream lub czegoś innego. Ponieważ jest to normalna klasa .NET, jest zarządzana. Ale jest to wrapper, który w środku wykonuje „brudną robotę” (komunikuje się z systemem operacyjnym za pomocą bibliotek DLL Win32, wywołuje funkcje niskiego poziomu, a nawet instrukcje asemblera), który naprawdę otwiera plik. I to jest to, o czym .NET nie wie, niezarządzane. Ale być może możesz otworzyć plik samodzielnie, korzystając z instrukcji asemblera i ominąć funkcje pliku .NET. Wtedy dojście i otwarty plik są zasobami niezarządzanymi.

To samo z DB: jeśli używasz jakiegoś zestawu DB, masz klasy takie jak DbConnection itp., Są one znane w .NET i zarządzane. Ale pakują „brudną robotę”, która jest niezarządzana (alokacja pamięci na serwerze, nawiązanie z nim połączenia, ...). Jeśli nie używasz tej klasy opakowania i samodzielnie otwierasz jakieś gniazdo sieciowe i komunikujesz się z własną dziwną bazą danych za pomocą niektórych poleceń, to nie jest zarządzana.

Te klasy opakowania (File, DbConnection itp.) Są zarządzane, ale wewnątrz używają niezarządzanych zasobów w taki sam sposób jak Ty, jeśli nie używasz opakowań i samodzielnie wykonujesz „brudną robotę”. I dlatego te opakowania implementują wzorce Dispose / Finalize. Do ich obowiązków należy zezwolenie programiście na zwolnienie niezarządzanych zasobów, gdy opakowanie nie jest już potrzebne, i zwolnienie ich, gdy opakowanie jest usuwane jako śmieci. Opakowanie będzie poprawnie zbierane przez moduł wyrzucania elementów bezużytecznych, ale niezarządzane zasoby wewnątrz zostaną zebrane przy użyciu wzorca Dispose / Finalize.

Jeśli nie używasz wbudowanych klas opakowujących .NET lub innych firm i nie otwierasz plików przez niektóre instrukcje asemblera itp. W swojej klasie, te otwarte pliki są niezarządzane i MUSISZ zaimplementować wzorzec usuwania / finalizowania. Jeśli tego nie zrobisz, nastąpi wyciek pamięci, na zawsze zablokowany zasób itp., Nawet jeśli nie będziesz go już używać (operacja na plikach zakończona) lub nawet po zakończeniu działania aplikacji.

Ale twoja odpowiedzialność spoczywa również na tych opakowaniach. Dla tych, którzy implementują dispose / finalize (rozpoznajesz je, że implementują IDisposable), zaimplementuj również wzorzec dispose / finalize i pozbądź się nawet tych opakowań lub daj im sygnał do zwolnienia niezarządzanych zasobów. Jeśli tego nie zrobisz, zasoby zostaną zwolnione po pewnym nieokreślonym czasie, ale natychmiastowe zwolnienie jest czyste (natychmiast zamknij plik i nie pozostawiaj go otwartego i zablokowanego przez kilka minut / godzin). Dlatego w metodzie Dispose klasy wywołujesz metody Dispose wszystkich używanych opakowań.

Martas
źródło
1
Dobrze, jeśli chodzi o dodatkową jasnośćunmanaged vs managed resources
teraz ten, którego nie można nazwać.
dzięki za odpowiedź. które klasy są zalecane, aby faktycznie wywołać metodę Dispose?
BKSpurgeon
2
To jest proste. Na każdej klasie, której używasz, musisz sprawdzić, czy implementuje interfejs IDisposable. Jeśli tak, to jeśli używasz takiej klasy w jednej metodzie (np .: otwieranie pliku, zapisywanie tekstu, zamykanie pliku), możesz tego użyć za pomocą wzorca () {}, który automatycznie wywoła Dispose. Jeśli używasz takiej klasy w większej liczbie metod (np: twoja klasa zawiera File, w konstruktorze otwiera plik, następnie kilka metod dodaje trochę logów ...), to musisz zaimplementować interfejs IDisposable w swojej klasie, zaimplementuj wzorzec Dispose / Finalize i odpowiednio pozbyć się przedmiotu tej klasy.
Martas
1
„... jakaś wbudowana klasa .NET System.IO.File, FileStream lub coś innego. Ponieważ jest to normalna klasa .NET, jest zarządzana”. Z całym szacunkiem, jest to błędne i mylące. Nie są zarządzane . Gdyby były zarządzane, można by przydzielić te klasy i oczekiwać, że moduł odśmiecania pamięci w pełni obsłuży zwolnienie wszystkich zasobów w sposób deterministyczny. Spowoduje to jednak, że dojścia plików i niezarządzane zasoby zostaną zablokowane i przetrzymywane znacznie dłużej niż to konieczne, ponieważ moduł odśmiecania pamięci nie zwolni przydziału klasy i nie zakończy jej przez potencjalnie bardzo długi czas.
AaronLS
1
@AaronLS w swoim komentarzu wspomniałeś o „FileStream”, określając go jako niezarządzanego, ale tak nie jest, chociaż wewnętrznie wykorzystuje niezarządzane zasoby do wykonania swojej pracy.W zarządzanym świecie firma Microsoft ukryła przed Tobą wiele niezarządzanych rzeczy, implementując pozbyć się wzoru. Kod zarządzany nie oznacza, że ​​nie używa niezarządzanych zasobów. Jednak firma Microsoft wykonała dobrą robotę, implementując IDisposable na tego typu obiektach. Świadczy o tym fakt, że implementuje IDisposable. W odniesieniu do tego dowodu powinniśmy uznać go za obiekt zarządzany.
Malik Khalil
12

Zasoby niezarządzane to te, które działają poza środowiskiem wykonawczym .NET (CLR) (czyli kod inny niż .NET). Na przykład wywołanie biblioteki DLL w interfejsie API Win32 lub wywołanie pliku .dll napisanego w języku C ++.

David
źródło
6

„Niezarządzany zasób” nie jest rzeczą, ale odpowiedzialnością. Jeśli obiekt jest właścicielem niezarządzanego zasobu, oznacza to, że (1) jakiś obiekt znajdujący się poza nim został zmanipulowany w sposób, który może powodować problemy, jeśli nie zostanie wyczyszczony, oraz (2) obiekt posiada informacje niezbędne do wykonania takiego czyszczenia i jest odpowiedzialny za zrobienie tego.

Chociaż wiele typów niezarządzanych zasobów jest bardzo silnie powiązanych z różnymi typami jednostek systemu operacyjnego (pliki, uchwyty GDI, alokowane bloki pamięci itp.), Nie istnieje jeden typ jednostki, który byłby współdzielony przez wszystkie z nich poza odpowiedzialnością sprzątać. Zwykle jeśli obiekt jest odpowiedzialny za wykonanie czyszczenia, będzie miał metodę Dispose, która instruuje go, aby przeprowadził wszystkie operacje czyszczenia, za które jest odpowiedzialny.

W niektórych przypadkach obiekty uwzględniają możliwość ich porzucenia bez wcześniejszego wywołania metody Dispose. GC umożliwia obiektom żądanie powiadomienia, że ​​zostały porzucone (przez wywołanie procedury o nazwie Finalize), a obiekty mogą używać tego powiadomienia do samodzielnego czyszczenia.

Terminy takie jak „zarządzany zasób” i „niezarządzany zasób” są niestety używane przez różnych ludzi w różnym znaczeniu; szczerze mówiąc uważam, że bardziej przydatne jest myślenie w kategoriach obiektów, które albo nie ponoszą żadnej odpowiedzialności za sprzątanie, mają odpowiedzialność za sprzątanie, która zostanie załatwiona tylko w przypadku wywołania metody Dispose, lub jako odpowiedzialność za sprzątanie, którą należy załatwić za pośrednictwem usługi Dispose, ale którą można zajmie się również Finalize.

superkat
źródło
5

Podstawowa różnica między zasobem zarządzanym i niezarządzanym polega na tym, że moduł wyrzucania elementów bezużytecznych wie o wszystkich zarządzanych zasobach, w pewnym momencie pojawi się GC i wyczyści całą pamięć i zasoby skojarzone z zarządzanym obiektem. GC nie wie o niezarządzanych zasobach, takich jak pliki, strumienie i uchwyty, więc jeśli nie wyczyścisz ich jawnie w swoim kodzie, skończy się to z wyciekami pamięci i zablokowanymi zasobami.

Skradziony stąd , zapraszam do przeczytania całego postu.

Marko
źródło
2

Każdy zasób, dla którego przydzielono pamięć w stercie zarządzanym .NET, jest zasobem zarządzanym. CLR jest całkowicie świadomy tego rodzaju pamięci i zrobi wszystko, aby upewnić się, że nie zostanie on osierocony. Wszystko inne jest niezarządzane. Na przykład współdziałanie z COM może tworzyć obiekty w przestrzeni pamięci procesu, ale CLR nie zajmie się tym. W takim przypadku obiekt zarządzany, który wykonuje wywołania w granicach zarządzanych, powinien odpowiadać za wszystko poza nim.

Soundararajan
źródło
0

Najpierw zrozumiemy, w jaki sposób były uruchamiane programy w języku VB6 lub C ++ (aplikacje inne niż Dotnet). Wiemy, że komputery rozumieją tylko kod na poziomie maszyny. Kod na poziomie maszyny jest również nazywany kodem natywnym lub binarnym. Tak więc, kiedy wykonujemy program w VB6 lub C ++, odpowiedni kompilator języka kompiluje odpowiedni kod źródłowy języka na kod natywny, który może być następnie zrozumiany przez podstawowy system operacyjny i sprzęt.

Kod natywny (kod niezarządzany) jest specyficzny (natywny) dla systemu operacyjnego, w którym jest generowany. Jeśli weźmiesz ten skompilowany kod natywny i spróbujesz uruchomić go w innym systemie operacyjnym, zakończy się niepowodzeniem. Tak więc problem z tym stylem wykonywania programów polega na tym, że nie można go przenosić z jednej platformy na inną.

Zrozummy teraz, jak działa program .Net. Za pomocą dotnet możemy tworzyć różne typy aplikacji. Kilka popularnych typów aplikacji .NET obejmuje aplikacje WWW, Windows, konsole i aplikacje mobilne. Niezależnie od typu aplikacji, po uruchomieniu dowolnej aplikacji .NET dzieje się co następuje

  1. Aplikacja .NET zostaje skompilowana do języka pośredniego (IL). IL jest również określany jako wspólny język pośredni (CIL) i język pośredni firmy Microsoft (MSIL). Aplikacje .NET i inne niż .NET generują zestaw. Zestawy mają rozszerzenie .DLL lub .EXE. Na przykład, jeśli kompilujesz aplikację Windows lub konsolę, otrzymujesz .EXE, gdzie tak jak podczas kompilacji projektu sieci lub biblioteki klas otrzymujemy .DLL. Różnica między zestawem .NET i innym niż .NET polega na tym, że zestaw DOTNET jest w formacie języka pośredniego, podczas gdy zestaw NON DOTNET jest w formacie kodu natywnego.

  2. Aplikacje inne niż DOTNET mogą działać bezpośrednio w systemie operacyjnym, podczas gdy aplikacje DOTNET działają w środowisku wirtualnym zwanym Common Language Runtime (CLR). CLR zawiera komponent o nazwie Just In-Time Compiler (JIT), który konwertuje język pośredni na kod natywny zrozumiały dla podstawowego systemu operacyjnego.

Tak więc w .NET wykonanie aplikacji składa się z 2 kroków 1. Kompilator języka, kompiluje kod źródłowy do języka pośredniego (IL) 2. Kompilator JIT w CLR konwertuje IL na kod natywny, który można następnie uruchomić w podstawowym systemie operacyjnym .

Ponieważ zestaw .NET jest w formacie języka Intermedaite, a nie w kodzie natywnym, zestawy .NET są przenośne na dowolną platformę, o ile platforma docelowa ma środowisko uruchomieniowe języka wspólnego (CLR). Środowisko CLR platformy docelowej konwertuje język Intermedaite na kod natywny, który może zrozumieć podstawowy system operacyjny. Język pośredni jest również nazywany kodem zarządzanym. Dzieje się tak, ponieważ CLR zarządza kodem, który w nim działa. Na przykład w programie VB6 programista jest odpowiedzialny za cofnięcie alokacji pamięci używanej przez obiekt. Jeśli programista zapomni o zwolnieniu pamięci, możemy napotkać trudne do wykrycia wyjątki braku pamięci. Z drugiej strony programista .NET nie musi martwić się o cofnięcie alokacji pamięci zajmowanej przez obiekt. Automatyczne zarządzanie pamięcią, nazywane również zbieraniem pobierania, jest zapewniane przez środowisko CLR. Niezależnie, z wyrzucania elementów bezużytecznych CLR zapewnia kilka innych korzyści, które omówimy w późniejszej sesji. Ponieważ CLR zarządza i wykonuje język pośredni, jest on również nazywany kodem zarządzanym.

.NET obsługuje różne języki programowania, takie jak C #, VB, J # i C ++. C #, VB i J # mogą generować tylko kod zarządzany (IL), gdzie jako C ++ może generować zarówno kod zarządzany (IL), jak i kod niezarządzany (kod natywny).

Natywny kod nie jest nigdzie przechowywany na stałe, po zamknięciu programu natywny kod jest wyrzucany Kiedy ponownie uruchomimy program, kod natywny zostanie ponownie wygenerowany.

Program .NET jest podobny do wykonywania programu Java. W javie mamy kody bajtowe i JVM (Java Virtual Machine), natomiast tak jak w .NET mamy język pośredni i CLR (Common Language Runtime)

Zapewnia to ten link - jest świetnym nauczycielem. http://csharp-video-tutorials.blogspot.in/2012/07/net-program-execution-part-1.html

himanshupareek66
źródło