2009-11-09 8 views
5

Wiele lat temu, gdy tylko było to możliwe, upominano mnie, by udostępniać zasoby w odwrotnej kolejności, w jaki sposób zostały przydzielone. Czyli:C#: Czy istnieje korzyść w dysponowaniu zasobami w odwrotnej kolejności ich alokacji?

block1 = malloc(...); 
block2 = malloc(...); 

... do stuff ... 

free(block2); 
free(block1); 

sobie wyobrazić na maszynie 640 KB MS-DOS, może to zminimalizować fragmentacji sterty. Czy jest jakaś praktyczna korzyść, aby to zrobić w aplikacji C# /.NET, czy jest to nawyk, który przeżył jego znaczenie?

Odpowiedz

5

Jeśli zasoby są dobrze stworzone, nie powinno to mieć znaczenia (dużo).

Jednak wiele źle utworzonych bibliotek nie sprawdza poprawnie. Utylizacja zasobów w odwrotnej kolejności niż zwykle oznacza, że ​​najpierw dysponujesz zasobami zależnymi od innych zasobów, co może uniemożliwić powstanie problemów w źle napisanych bibliotekach. (Nigdy nie wyrzucaj zasobu, a następnie używaj go, który zależy od tego, w którym przypadku istnieje).

Jest to również dobra praktyka, ponieważ nie zamierzasz przypadkowo wyładować zasobu wymaganego przez jakiś inny obiekt zbyt wcześnie .

Oto przykład: spójrz na operację bazy danych. Nie chcesz zamykać/usuwać połączenia przed zamknięciem/wyrzuceniem komendy (która korzysta z połączenia).

+0

Dobrze stworzony nie jest dobry. Musi być zależne od zlecenia, zależne od wydania i znane w wielu okolicznościach. Nie może mieć większego znaczenia we wszystkich implementacjach baz danych, transakcji i wszystkiego, co działa na stosie (większość oprogramowania tam jest). Blokady są kolejnym przykładem i stosy bibliotek nie-zewnętrznych i ubogich używają go. Operacje plików i ich blokady są inne. Incydent zdarzeń inny. Wszelkie zasoby niezarządzane w zależności od jeszcze innego. Stworzenie i zniszczenie idą w parze, a idiomu nie można łamać w kategoriach Inicjacji Zasobów-Jest- "dobrze-Stworzenie". –

+0

Tak więc WC w oksymoronie RIIWC zastąpiono Akwizycją, co implikuje Uwolnienie btw. A ponieważ pamięć i duża ilość zasobów są w większości wyabstrahowane, ops, pojawia się pomysł ... i powstają wszelkiego rodzaju hacki. Krótko mówiąc, jest to po prostu charakter problemu i ma duże znaczenie. –

+0

I chociaż nie bronię tutaj zależności od rzędu, prawidłowa obserwacja jest taka, że ​​jest niezwykle istotna, ale rzadko pożądana. Ale jest to coś, do czego ekstremalne specyfikacje VM są ograniczone. Java implikuje szczególnie i CLR w mniejszym, ale wciąż znacznym stopniu. Jest to hack, aby nie łamać dużych ilości działającego kodu i przyjętych założeń, świadomej decyzji kompilatora i projektantów JIT. Kod, który jest zdolny do niezależnego od zamówienia przetwarzania, daje wiele możliwości, ale może być niemożliwy do zrealizowania w wielu scenariuszach. –

4

Nie trudź się. GarbageCollector zastrzega sobie prawo do defragmentacji i przenoszenia obiektów na stercie, więc nie wiadomo, w jakiej kolejności znajdują się rzeczy.

Ponadto, jeśli dysponujesz odniesieniami A i B i A, nie powinno to mieć znaczenia, jeśli A zrzuca B, gdy pozbędziesz się A, ponieważ metoda Dispose powinna być wywoływana więcej niż jeden raz bez rzucania wyjątku.

+1

to prawda, pod warunkiem, że nie powinno się używać „zbyte "odniesienie przez przypadek (przez inny obiekt z niego utworzony), ponieważ dysponujesz arbitralnym ordem er. –

0

Zagnieżdżone "użytkowanie" pokazuje, że "przeżyty" nie jest tak naprawdę włączony, i rzadko (nie należy mówić i nigdy nie mówić po 40 latach dowodowych). A to obejmuje wirtualną maszynę opartą na stosie, która działa na przykład CMOS .

[Pomimo pewnych prób przez MSDN.com i Duffius, aby zniknąć, wiesz, zarządzaj całą tą różnicą między stertą a stosem. Co za sprytny pomysł ... w kosmosie]

1

Jeśli chodzi o czas, w którym destruktor obiektów zostanie wywołany, to jest to śmieciarz, programowanie może mieć bardzo mały wpływ na to, i jest explicity nie-deterministyczne zgodnie z definicją języka.

Jeśli chodzi o wywołanie IDisposable.Dispose(), zależy to od zachowania obiektów implementujących interfejs IDisposable.

Ogólnie rzecz biorąc, kolejność nie ma znaczenia dla większości obiektów Framework, z wyjątkiem zakresu, w jakim ma to znaczenie dla kodu wywołującego. Ale jeśli obiekt A zachowuje zależność od obiektu B, a obiekt B jest ułożony, to może być bardzo ważne, aby nie robić pewnych rzeczy z obiektem A.

W większości przypadków funkcja Dispose() nie jest wywoływana bezpośrednio, ale raczej nazywa się to niejawnie jako część instrukcji użycia lub foreach, w którym to przypadku wzór odwrotnego porządku pojawi się naturalnie, zgodnie z osadzeniem oświadczenia.

using(Foo foo = new Foo()) 
using(FooDoodler fooDoodler = new FooDoodler(foo)) 
{ 
    // do stuff 
    // ... 
    // fooDoodler automatically gets disposed before foo at the end of the using statement. 
} 
0

„Środowisko wykonawcze nie czyni żadnych gwarancji co do kolejności, w jakiej są nazywane sfinalizować metody. Na przykład, powiedzmy, że nie jest obiektem, który zawiera wskaźnik do wewnętrznej obiektu.Śmieciarz wykrył, że oba obiekty są śmieciami. Co więcej, powiedzmy, że metoda finalizacji obiektu wewnętrznego zostaje wywołana jako pierwsza. Teraz metoda finalizacji obiektu zewnętrznego może uzyskać dostęp do obiektu wewnętrznego i metod wywoływania na nim, ale obiekt wewnętrzny został sfinalizowany, a wyniki mogą być nieprzewidywalne. Z tego powodu zaleca się, że metody sfinalizować nie mieli dostępu do żadnych wewnętrznych, obiektów członków.”

http://msdn.microsoft.com/en-us/magazine/bb985010.aspx

Więc można martwić się o swoje LIFO unieszkodliwiają semantyki tyle, ile chcesz, ale jeśli wyciek onem, Dispose() 's będą nazywane w dowolnej kolejności do upodobań CLR.

(to jest mniej więcej to, co powiedział Will, powyżej)

Powiązane problemy