Czytałem w wielu miejscach (cholera, nawet sam tak napisałem), że zbieranie śmieci może (teoretycznie) być szybsze niż ręczne zarządzanie pamięcią.
Jednak pokazywanie jest znacznie trudniejsze niż opowiadanie.
Tak naprawdę nigdy nie widziałem żadnego kodu, który demonstruje ten efekt w działaniu.
Czy ktoś ma (lub wie, gdzie mogę znaleźć) kod, który demonstruje tę przewagę wydajności?
memory
garbage-collection
Mehrdad
źródło
źródło
Odpowiedzi:
Zobacz http://blogs.msdn.com/b/ricom/archive/2005/05/10/416151.aspx i skorzystaj ze wszystkich linków, aby zobaczyć, jak Rico Mariani kontra Raymond Chen (obaj bardzo kompetentni programiści w Microsoft) pojedynkują się . Raymond poprawiłby ten niezarządzany, Rico zareagowałby optymalizując to samo w zarządzanych.
Przy praktycznie zerowym nakładzie pracy na optymalizację, zarządzane wersje zaczęły działać wiele razy szybciej niż podręcznik. Ostatecznie instrukcja pokonała zarządzany, ale tylko poprzez optymalizację do poziomu, do którego większość programistów nie chciałaby pójść. We wszystkich wersjach użycie pamięci podręcznika było znacznie lepsze niż zarządzane.
źródło
swap
) nie jest takie trudne i prawdopodobnie doprowadziłoby cię tam dość łatwo pod względem wydajności ...Ogólna zasada jest taka, że nie ma bezpłatnych obiadów.
GC eliminuje problemy związane z ręcznym zarządzaniem pamięcią i zmniejsza prawdopodobieństwo popełnienia błędów. Są sytuacje, w których określona strategia GC jest optymalnym rozwiązaniem problemu, w którym to przypadku nie zapłacisz kary za korzystanie z niej. Ale są też inne, w których inne rozwiązania będą szybsze. Ponieważ zawsze możesz symulować wyższe abstrakcje z niższego poziomu, ale nie na odwrót, możesz skutecznie udowodnić, że w żaden sposób wyższe abstrakcje nie mogą być szybsze niż niższe w ogólnym przypadku.
GC to szczególny przypadek ręcznego zarządzania pamięcią
Ręczne uzyskanie lepszej wydajności może wymagać dużo pracy lub więcej błędów, ale to inna historia.
źródło
Łatwo jest skonstruować sztuczną sytuację, w której GC jest nieskończenie wydajniejszy niż metody ręczne - po prostu ustal, że istnieje tylko jeden „root” dla śmietnika, i że wszystko jest śmieci, więc krok GC jest natychmiast ukończony.
Jeśli się nad tym zastanowić, jest to model używany podczas wyrzucania elementów bezużytecznych do pamięci przydzielonej procesom. Proces umiera, cała pamięć to śmieci, gotowe. Nawet w praktyce proces, który się uruchamia, uruchamia i umiera, nie pozostawiając śladu, może być bardziej wydajny niż proces, który uruchamia się i działa na zawsze.
W przypadku praktycznych programów napisanych w językach z funkcją odśmiecania zaletą nie jest szybkość, lecz poprawność i prostota.
źródło
abort()
w C ++ przed zamknięciem programu. To bezsensowne porównanie; nawet nie zbierasz śmieci, po prostu pozwalasz na wyciek pamięci. Nie można powiedzieć, że zbieranie śmieci jest szybsze (lub wolniejsze), jeśli nie zbieracie śmieci na początek ...Należy wziąć pod uwagę, że GC to nie tylko strategia zarządzania pamięcią; nakłada także wymagania na cały projekt języka i środowiska wykonawczego, co wiąże się z kosztami (i korzyściami). Na przykład język, który obsługuje GC, musi zostać skompilowany do postaci, w której wskaźników nie można ukryć przed śmieciarzem, i ogólnie tam, gdzie nie można ich zbudować, chyba że przez starannie zarządzane operacje podstawowe systemu. Inną kwestią jest trudność z utrzymaniem gwarancji czasu reakcji, ponieważ GC nakłada pewne kroki, które należy wykonać, aby zakończyć.
W związku z tym, jeśli masz język, w którym zbierane są śmieci, i porównujesz szybkość z ręcznie zarządzaną pamięcią w tym samym systemie, nadal musisz zapłacić koszty ogólne, aby wesprzeć zbieranie śmieci, nawet jeśli go nie używasz.
źródło
Szybsze jest wątpliwe. Może być jednak bardzo szybki, niezauważalny lub szybszy, jeśli jest obsługiwany sprzętowo. Podobne konstrukcje dla maszyn LISP już dawno temu. Jeden wbudował GC w podsystem pamięci urządzenia jako taki, że główny procesor nie wiedział, że tam jest. Podobnie jak wiele późniejszych projektów, GC działało równolegle z głównym procesorem z niewielkimi lub żadnymi przerwami. Bardziej nowoczesnym designem są maszyny Azul Systems Vega 3, które uruchamiają kod Java znacznie szybciej niż JVM z wykorzystaniem specjalnie zaprojektowanych procesorów i bez przerwy GC. Google, jeśli chcesz wiedzieć, jak szybka może być GC (lub Java).
źródło
Zrobiłem w tym sporo pracy i opisałem niektóre z nich tutaj . Testowałem Boehm GC w C ++, alokując za pomocą,
malloc
ale nie uwalniając, alokując i zwalniając za pomocąfree
i GC napisany w C ++ wszystko w porównaniu do podstawowego GC OCaml działającego na liście Solver n-queens. GC OCaml był szybszy we wszystkich przypadkach. Programy C ++ i OCaml zostały celowo napisane, aby wykonać te same alokacje w tej samej kolejności.Można oczywiście przepisać programy w celu rozwiązania problemu, używając tylko 64-bitowych liczb całkowitych i bez przydziałów. Chociaż szybsze, to pokonałoby punkt ćwiczenia (który polegał na przewidywaniu wydajności nowego algorytmu GC, nad którym pracowałem przy użyciu prototypu zbudowanego w C ++).
Wiele lat spędziłem w branży, przenosząc prawdziwy kod C ++ na języki zarządzane. W prawie każdym przypadku zaobserwowałem znaczną poprawę wydajności, z których wiele prawdopodobnie wynikało z ręcznego zarządzania pamięcią przez GC. Praktyczne ograniczenie nie polega na tym, co można osiągnąć za pomocą znaku mikrodruku, ale na tym, co można osiągnąć przed upływem terminu, a języki oparte na GC oferują tak ogromne zwiększenie wydajności, że nigdy nie spojrzałem wstecz. Nadal używam C i C ++ na urządzeniach wbudowanych (mikrokontrolerach), ale nawet to się teraz zmienia.
źródło
List.filter
podobnie jak C ++. Ale tak, z pewnością masz rację, że niektóre operacje RC można uniknąć. Jednak największym problemem, jaki widzę na wolności, jest to, że ludzie nie mają czasu na ręczne przeprowadzanie takich optymalizacji na dużych bazach kodu przemysłowego.shared_ptr
aby naprawić błędy współbieżności. Kod jest dużo wolniejszy, ale hej, teraz działa.Taki przykład niekoniecznie ma zły schemat ręcznej alokacji pamięci.
Załóż najlepszy zbieracz śmieci
GC
. Ma wewnętrznie metody alokacji pamięci, określania, którą pamięć można zwolnić oraz metody jej ostatecznego uwolnienia. Razem zajmują mniej czasu niż wszystkieGC
; trochę czasu spędza się na innych metodachGC
.Rozważmy teraz ręczny alokator, który korzysta z tego samego mechanizmu alokacji co
GC
i któregofree()
wywołanie tylko odsuwa pamięć na tę samą metodę, coGC
. Nie ma fazy skanowania ani żadnej innej metody. To z konieczności zajmuje mniej czasu.źródło
free
może również zbierać partie. (I oczywiście usunięcie wszystkich pozycji spełniających kryterium jest wciąż O (N), choćby z powodu samej przejścia listy)free
może działać w trybie zbierania wsadowego, jeśli każdy element pamięci ma powiązaną z nim flagę, chociaż GC wciąż może wyjść na przód w niektórych sytuacjach. Jeśli ktoś ma M referencji, które identyfikują L odrębnych pozycji z zestawu N rzeczy, czas na usunięcie każdego odwołania, do którego nie ma żadnego odniesienia, i utrwalenie reszty to O (M) zamiast O (N). Jeśli jest dostępne M dodatkowej przestrzeni, stała skalowania może być dość mała. Ponadto, kompaktowanie w