2016-07-07 9 views
5

Mam nadzieję, że to pytanie nie jest zbyt otwarte. Wpadłem na problem z pamięcią z Rust, gdzie dostałem an "out of memory" from calling next on an Iterator trait object. Nie jestem pewien, jak to debugować. Wydruki doprowadziły mnie tylko do punktu, w którym nastąpiła awaria. Nie jestem zaznajomiony z innymi narzędziami, takimi jak ltrace, więc chociaż mogłem stworzyć ślad (231MiB, pff), tak naprawdę nie wiedziałem, co z tym zrobić. Czy taki ślad jest użyteczny? Czy powinienem lepiej pobrać gdb/lldb? Lub Valgrind?Jak mogę debugować problem z pamięcią w Rust?

+0

Valgrind jest zawsze dobrym początkiem. Spróbuj również zoptymalizować swój kod. –

+2

@EliSadoff Jak optymalizacja mojego kodu pomaga w debugowaniu problemów z pamięcią? – Apanatshka

Odpowiedz

3

Generalnie chciałbym spróbować wykonać następujące podejście:

  1. boilerplate zniżki: Spróbuj zawęzić problem OOM, tak, że nie masz zbyt dużo dodatkowego kodu dookoła. Innymi słowy: im szybciej twój program się zawiesza, tym lepiej. Czasami możliwe jest wyrwanie określonego kodu i umieszczenie go w dodatkowym pliku binarnym, tylko na potrzeby dochodzenia. rozdrabnianie

  2. Problem: Dolna problem z OOM do prostego „zbyt dużo pamięci”, tak, że rzeczywiście można powiedzieć coś niektóre odpady części, lecz że nie doprowadzi do OOM. Jeśli trudno jest stwierdzić, czy problem występuje, czy nie, można zmniejszyć limit pamięci. W systemie Linux, można to zrobić za pomocą ulimit: gromadzenie

    ulimit -Sv 500000 # that's 500MB 
    ./path/to/exe --foo 
    
  3. informacje: Jeśli problemem jest wystarczająco mały, jesteś gotowy do zbierania informacji, który ma niższy poziom hałasu. Istnieje wiele sposobów, które możesz wypróbować. Pamiętaj tylko, aby skompilować program za pomocą symboli debugowania. Również wyłączenie optymalizacji może być korzystne, ponieważ zazwyczaj prowadzi to do utraty informacji. Obie mogą być archiwizowane przez NIE przy użyciu flagi --release podczas kompilacji.

    • Heap profilowanie: Jednym ze sposobów jest zbyt używać gperftools:

      LD_PRELOAD="/usr/lib/libtcmalloc.so" HEAPPROFILE=/tmp/profile ./path/to/exe --foo 
      pprof --gv ./path/to/exe /tmp/profile/profile.0100.heap 
      

      To pokazuje wykres, która symbolizuje które części programu jeść która to ilość pamięci. Aby uzyskać więcej informacji, patrz official docs.

    • rr: Czasami bardzo trudno jest ustalić, co się naprawdę dzieje, szczególnie po utworzeniu profilu. Zakładając, że dobrą robotę w kroku 2, można użyć rr:

      rr record ./path/to/exe --foo 
      rr replay 
      

      To będzie tarło GDB z supermocarstw. Różnica w stosunku do zwykłej sesji debugowania polega na tym, że można nie tylko continue, ale także reverse-continue. Zasadniczo program jest wykonywany z nagrania, w którym można przeskakiwać w dowolne miejsce. This wiki page podaje dodatkowe przykłady. Należy zwrócić uwagę na to, że rr działa tylko z GDB.

    • Dobre stare debugowanie: Czasami można uzyskać ślady i nagrania, które są zbyt duże. W takim przypadku można (w połączeniu z ulimit podstęp) wystarczy użyć GDB i czekać aż wywala program:

      gdb --args ./path/to/exe --foo 
      

      Teraz powinien dostać normalną debugowania sesji, gdzie można sprawdzić jaki jest aktualny stan programu było . GDB można również uruchomić za pomocą coredump. Ogólny problem z tym podejściem polega na tym, że nie można cofnąć się w czasie i nie można kontynuować wykonywania. Widzisz tylko bieżący stan, w tym wszystkie klatki stosu i zmienne. Tutaj możesz również użyć LLDB, jeśli chcesz.

  4. (Potential) fix + powtórki: Po masz klej, co może pójść źle, możesz spróbować zmienić swój kod. Następnie spróbuj ponownie. Jeśli nadal nie działa, wróć do kroku 3 i spróbuj ponownie.

1

Ogólnie rzecz biorąc, do debugowania można użyć podejścia opartego na logowaniu (albo wstawiając dzienniki samodzielnie, albo mając narzędzie takie, jak ltrace, ptrace, ... aby wygenerować dzienniki dla ciebie) lub możesz użyj debuggera.

Należy pamiętać, że metody oparte na debuggerze wymagają, aby można było odtworzyć problem; Mam tendencję do faworyzowania ręcznych dzienników, ponieważ pracuję w branży, w której raporty o błędach są generalnie zbyt nieprecyzyjne, aby umożliwić natychmiastową reprodukcję (a zatem używamy dzienników do tworzenia scenariusza dla reproduktorów).

Rust obsługuje oba podejścia, a standardowy zestaw narzędzi, którego używa się w programach C lub C++, działa dobrze.

Moim osobistym podejściem jest rejestrowanie się w jednym miejscu, aby szybko zawęzić miejsce, w którym wystąpił problem, a jeśli logowanie nie wystarcza do uruchomienia debuggera w celu dokładniejszego sprawdzenia. W tym przypadku polecam od razu przejść do debuggera. Wygenerowano

Wygenerowano panic, co oznacza, że ​​poprzez przerwanie połączenia z hakiem paniki, zobaczysz zarówno stos wywołań, jak i stan pamięci w momencie, gdy coś pójdzie nie tak.

Uruchom program za pomocą debuggera, ustaw punkt przerwania na hak wywoływania paniki, uruchom program, zysk.

Powiązane problemy