2009-04-13 10 views
12

Jeśli prowadzę długotrwałą aplikację, taką jak serwer WWW w ramach obrazu wspólnego Lisp, jaką strategię powinienem użyć do zarządzania śmieciarzem?W długotrwałej aplikacji Common Lisp, jakiej strategii należy użyć do zarządzania odpadami?

Domyślam się, że odśmiecacz jest uprawniony do spędzania długich okresów sortowania sterty, czasami nie mogę przewidzieć. Może to wpłynąć na konkretne żądanie przeglądarki w sposób, którego nie chcę.

Czy istnieje metoda w Common Lisp, aby to kontrolować? Być może zachęcając go do pracy w sposób "mało i często"?

+0

Którą implementację seplenia używasz? – Zifre

+0

Kiedy mówisz "zakładam", brzmi to tak, jakbyś próbował robić optymalizacje bez konieczności profilowania. Czy widzisz konkretne problemy, które wymagają naprawy w Twoim środowisku? – Ken

+0

Zaczynam proces informowania się o problemach, które jeszcze się nie pojawiły. Biorąc pod uwagę liczbę języków GC używanych w usługach internetowych, zakładam, że jest to w dużym stopniu rozwiązany problem. –

Odpowiedz

24

Kilka implementacji Lisp ma znakomitych Garbage Collectorów. Szczególnym problemem jest to, że aplikacje Lisp często mają wysoką szybkość alokacji małych obiektów (konektory, ...).

Jest kilka rzeczy do rozważenia.

  • Precise vs. Conservative GC. Nie jestem wielkim fanem konserwatywnych GC (Boehm itp.) Dla Lispa. Problem konserwatywnych GC polega na tym, że nie znajdują wszystkich śmieci. Może to stanowić problem dla długotrwałych programów i prowadzić do fragmentacji, a nie odzyskać niewykorzystanej pamięci. Precyzyjni GC używają informacji znaczników danych Lisp i mogą identyfikować każdy typ danych każdego obiektu. Konserwatywne GC zostały wynalezione do implementacji języków programowania, które nie używają oznaczonych danych (C++, ...).

  • kopiowanie GC, kompaktowanie GC. Aby przeciwdziałać fragmentacji pamięci w długotrwałym Lisps, przydatna może być GC, która kompaktuje i lokalizuje obiekty. Czasami pojawia się problem, gdy hashtables należy ponownie włączyć (ponieważ zmiany lokalizacji). Kopiujący GC może potrzebować więcej pamięci (ponieważ istnieje pamięć typu "from" i "a"). Ale gdy GC kopiuje obiekty z jednej przestrzeni pamięci do drugiej, automatycznie czyni ją bardziej zwartą. Bardziej zaawansowane GC (jak na Lisp Machine) mogą także sortować obiekty i przydzielać obiekty tego samego typu blisko siebie - zakładając, że przyspieszy to dostęp do obiektów.

  • efemeryczna GC. Oznacza to, że istnieje pierwszy etap GC, który działa wyłącznie w pamięci głównej i otrzymuje pewne wsparcie z jednostki zarządzania pamięcią, aby zidentyfikować zmienione obszary pamięci. Skanowanie pamięci głównej przebiega szybko, niż skanowanie pamięci wirtualnej, a zmiana obszarów pamięci tylko na skanowanie zmniejsza nakład pracy. Kiedy wiele obiektów jest przydzielanych i szybko zmienia się w śmieci, daje to bardzo krótkie przerwy GC.

  • pokoleniowy GC. Zazwyczaj GC obecnie są pokoleniowe. Istnieje więcej niż jedno pokolenie, a obiekty, które przetrwają kilka GC, są promowane do starszego pokolenia. Zwykle tylko pierwsza generacja GCed bardzo często.

  • Tuning. GC, powiedzmy, LispWorks i Allegro CL mają wiele gałek dostrajania. Zwłaszcza w przypadku długotrwałych aplikacji warto przeczytać instrukcję i na przykład dostroić liczbę pokoleń, ich rozmiary i inne rzeczy.

  • pamięć wirtualna. GC nad pamięcią wirtualną jest zwykle bardzo powolne.Unikaj tego, jeśli to możliwe - dodaj więcej pamięci RAM do komputerów.

  • ręczne zarządzanie pamięcią. Na przykład serwer WWW CL-HTTP wykonuje pewne ręczne zarządzanie pamięcią przy użyciu zasobów. Są to pule wstępnie przydzielonych obiektów, które można bardzo szybko zainicjować. Maszyny Lisp używały tego bardzo. Typowe ich użycie to odczyty buforów dla strumieni. Zamiast tworzyć nowe łańcuchy przy każdej operacji odczytu, przydatne jest użycie buforów wielokrotnego użytku.

  • alokacja stosu. Niektóre Common Lisp umożliwiają alokację w stos niektórych danych - opuszczenie bloku powoduje automatyczne zwolnienie pamięci. Zakłada to, że pamięć nie jest już przywoływana po opuszczeniu bloku.

  • równoczesne GC. Żadna ze zwykłych implementacji Common Lisp nie ma współbieżnego GC ORAZ wsparcia dla współbieżnych wątków Lisp. Niektóre implementacje mają współbieżne wątki Lisp, ale GC zatrzyma je wszystkie podczas pracy.

  • profilowanie GC. Jeśli nie masz pewności, gdzie odbywa się alokacja i co robi GC, musisz to znaleźć, korzystając z informacji profilujących.

Jeśli Twój Lisp ma precyzyjną pokoleniową GC, która działa w pamięci głównej, trudno jest mieć problemy z długimi przerwami. Clozure CL (darmowa implementacja Common Lisp) ma na przykład bardzo dobrą implementację GC. Chcesz uniknąć fragmentacji pamięci i zbierania śmieci w pamięci wirtualnej. Jeśli to konieczne, użyj 64-bitowej implementacji Lisp z większą pamięcią główną.

Wskaźniki:

można zobaczyć z dokumentacją LispWorks i Allegro CL ma wiele gałek do tuningu GC.

Common Lisp ma kilka funkcji związanych ze środowiskiem implementacji. (POKÓJ) to funkcja dająca przegląd zużycia pamięci. (POKÓJ t) podaje więcej szczegółów (tutaj LispWorks):

CL-USER 2 > (room t) 
Generation 0: Total Size 1823K, Allocated 1090K, Free 725K 
      Segment 2008AAB8: Total Size 507K, Allocated 361K, Free 142K 
        minimum free space 64K, 
         Awaiting promotion = 0K, sweeps before promotion =10 
      Segment 217E7050: Total Size 1315K, Allocated 729K, Free 582K 
        minimum free space 0K, 
         Awaiting promotion = 0K, sweeps before promotion =2 
Generation 1: Total Size 1397K, Allocated 513K, Free 871K 
      Segment 20CB9A50: Total Size 68K, Allocated 48K, Free 15K 
        minimum free space 0K, 
         Awaiting promotion = 0K, sweeps before promotion =4 
      Segment 216D7050: Total Size 1088K, Allocated 331K, Free 752K 
        minimum free space 0K, 
         Awaiting promotion = 0K, sweeps before promotion =4 
      Segment 2004E4F8: Total Size 241K, Allocated 133K, Free 103K 
        minimum free space 0K, static 
Generation 2: Total Size 2884K, Allocated 1290K, Free 1585K 
      Segment 21417050: Total Size 2816K, Allocated 1227K, Free 1584K 
        minimum free space 0K, 
         Awaiting promotion = 0K, sweeps before promotion =4 
      Segment 20DA5DA0: Total Size 68K, Allocated 62K, Free 1K 
        minimum free space 117K, 
         Awaiting promotion = 0K, sweeps before promotion =4 
Generation 3: Total Size 19373K, Allocated 19232K, Free 128K 
      Segment 20109A50: Total Size 11968K, Allocated 11963K, Free 0K 
        minimum free space 3K, 
         Awaiting promotion = 0K, sweeps before promotion =10 
      Segment 20DB6E18: Total Size 6528K, Allocated 6396K, Free 128K 
        minimum free space 0K, 
         Awaiting promotion = 0K, sweeps before promotion =10 
      Segment 20CCAAC8: Total Size 876K, Allocated 872K, Free 0K 
        minimum free space 0K, 
         Awaiting promotion = 0K, sweeps before promotion =10 

Total Size 25792K, Allocated 22127K, Free 3310K 
+0

Nie sądzę, aby twoje oświadczenie użycia tagu było całkowicie poprawne. Dokładny GC rzeczywiście zdecyduje, jak oczyścić, patrząc na znacznik obiektu (jak będzie nieprecyzyjny), ale najpierw musi wiedzieć, czy zawartość rejestru jest wskaźnikiem obiektu lub wartością natychmiastową. Ta ostatnia operacja oddziela precyzyjne od nieprecyzyjnych GC. – skypher

+0

Weź tablicę różnych rzeczy: obiektów natychmiastowych (liczby, znaki, ...) i obiektów nie bezpośrednich (tablica zawiera wskaźnik do nich: tablice, struktury, łańcuchy, ...).W jaki sposób GC wie, że jedna rzecz to liczba, a druga to wskaźnik (do struktury)? Konserwatywny GC został opracowany dla języków takich jak C i C++, gdzie nie ma żadnych oznaczonych obiektów. GC heurystycznie określa, co może być wskaźnikiem, a co nie. –

+0

Mogło zostać opracowane dla nieoznakowanych języków, takich jak C, ale jest używane nawet w niektórych środowiskach Lisp dzisiaj, np. CMUCL i SBCL używają konserwatywnego GC na architekturach "słabej jakości", takich jak x86: http: //sbcl-internals.cliki. net/GENCGC – Ken

2

Zbiór śmieci przeszedł długą drogę od wczesnych dni, a wiele pracy zostało zrobione, aby uniknąć nieprzewidywalnego długiego oczekiwania. W przypadku współczesnych wdrożeń uważam, że należą one do przeszłości.

Jednak szczegóły usuwania śmieci różnią się w zależności od implementacji. Nie ma tam zbyt wielu wysokiej jakości implementacji Lisp, więc nie powinieneś mieć trudności z zapoznaniem się z ich dokumentacją dotyczącą zbierania śmieci.