2013-04-17 12 views
26

Mój serwer dedykowany ma 32 GB pamięci RAM, a pamięć stale się podnosi i muszę ją codziennie restartować. To kosztuje mnie klientów i pieniądze.Jak znaleźć który skrypt PHP jest nieszczelny?

Mam trudności ze znalezieniem miejsca, w którym wyciek pamięci. Wszystko, co mogę znaleźć w Internecie, to ludzie mówią "Użyj xdebug", ale nie byłem w stanie znaleźć żadnych samouczków xdebug dotyczących znajdowania wycieków pamięci. Próbowałem drukować memory_get_usage przed i po wywołaniu funkcji, ale czy jest to właściwy sposób?

Mam wiele skryptów php działających - niektóre od odwiedzających, inne z zadań crona - i muszę znaleźć, który z nich jest wyciek pamięci i naprawić to jak najszybciej, ale nawet nie wiem, jak określić, czy dana funkcja przecieka pamięć lub nie.

Próbowałem drukować memory_get_usage przed wywołaniem funkcji i po, i idzie w górę, ale jeśli zadzwonię do tej funkcji więcej niż raz, to nie będzie już więcej. Czy ktoś może mi to wyjaśnić i powiedzieć, jak mogę łatwo i łatwo stwierdzić, czy funkcja PHP ma wyciek pamięci?

+0

Rozważałem to ... kopiowanie całej sprawy na inny serwer i uruchamianie tylko jednego elementu na raz i zobaczenie, co to powoduje. Kosztowne i czasochłonne ... Nie ma możliwości testowania pamięci w PHP? – Guy

+0

Nikt nie wiem. Jestem też ciekawy. Głosowałem za tobą i może oboje się dowiemy. –

+0

Zgadzam się z @ TomášZato.Możesz użyć skryptu 'auto_append_file' i' memory_get_ * ', aby zarejestrować wszystkie swoje skrypty i uważać na te ciężkie. – metadings

Odpowiedz

19

Można robić różne rzeczy, ale najpierw należy przede wszystkim unikać tworzenia przecieków pamięci.

Pozwól mi wyjaśnić: PHP jest językiem skryptowym i nie jest przeznaczony do długotrwałych skryptów, więc zarządzanie pamięcią nie jest najlepsze na rynku. Ale dlaczego miałoby to być? Jego celem jest wywoływanie na poziomie żądania, aby jego zakres działania był niewielki (nie więcej niż 2 - 3 sekundy). Cała reszta powinna być umieszczona w tle.

Co mogę zrobić, aby uniknąć wycieków pamięci?

  1. Jeśli jesteś w wersji poniżej 5.4, musisz zająć się odniesieniami do kół, ponieważ te nie są zebrane.

  2. Jeśli potrzebujesz skryptu, aby działał nieprzerwanie, możesz pomyśleć o innym podejściu. Wypróbuj implementację while(true), ale zawiń supervisor (http://supervisord.org) wokół swojego skryptu i pozwól, aby została wywołana po jej zakończeniu. W ten sposób uzyskasz 100% pewność, że nigdy nie dostaniesz wycieków pamięci.

  3. Możesz użyć xdebug, aby profilować swoje skrypty jeden po drugim i dowiedzieć się, gdzie zużywa się dużo pamięci.

  4. Można zaimplementować destruktor, aby usunąć wszystkie referencje, jeśli klasa nie jest już potrzebna.

    public function __destruct(){ 
        $this->cleanup(); 
    } 
    
    public function cleanup() { 
        //cleanup everything from attributes 
        foreach (get_class_vars(__CLASS__) as $clsVar => $_) { 
         unset($this->$clsVar); 
        } 
    
        //cleanup all objects inside data array 
        if (is_array($this->_data)) { 
         foreach ($this->_data as $value) { 
          if (is_object($value) && method_exists($value, 'cleanUp')) { 
           $value->cleanUp(); 
          } 
         } 
        } 
    } 
    
  5. Przeczytanie dokumentacji PHP dotyczące zbierania śmieci http://us3.php.net/manual/en/features.gc.php

  6. Unikać zmienne globalne, bo te nigdy nie są śmieci zbierane i muszą być unset wyraźnie. Jeśli używasz frameworka takiego jak ZF lub Symfony, co może nie być możliwe, ponieważ w przeciwnym razie możesz złamać funkcjonalność.

Ostatni, ale nie najmniej Chcę jeszcze raz podkreślić, PHP nie nadaje się do długich skryptów do biegania! Jeśli masz rzeczy do zrobienia, to trzeba uruchomić nieprzerwanie, nie powinieneś rozpadać się z powodu przecieków pamięci w PHP, ale poświęć czas, aby nauczyć się bardziej wyrafinowanego języka, takiego jak JAVA lub C#.

+0

A co ze zmiennymi referencyjnymi? –

1

Nie jestem ekspertem w wykorzystaniu pamięci, ale może ta metoda pomoże Ci wykryć problematyczne skrypty:

uzyskać informacje: 1. Użyj dostęp apache pliki dziennika 2. Stwórz własną zużycie pamięci plik dziennika (http://www.webhostingtalk.com/showthread.php?t=617742)

Sprawdź, kiedy zużycie pamięci rośnie i porównaj z dziennikiem dostępu apache.

Podadzą ci one przynajmniej informację, czy użytkowanie rośnie wolno i stale, czy też zaczyna się w określonym punkcie.

Powodzenia!

5

znalazłem metodę, która działa całkiem dobrze dla mnie:

  1. Install "php-memprof" przedłużeniu. W Ubuntu można uruchomić:

    sudo pecl install memprof

  2. Install "google-perftools". Znowu dla Ubuntu:

    sudo apt-get install google-perftools

  3. Dodaj ten kod na początku skryptu:

    if (function_exists('memprof_enable')) { 
        memprof_enable(); 
    } 
    
  4. I to aroud miejsce byłaś expexct znaleźć przeciek pamięci:

    if (function_exists("memprof_dump_pprof")) 
    { 
        $time = microtime(true); 
        $f = fopen("/tmp/profile_$time.heap", "w"); 
        memprof_dump_pprof($f); 
        fclose($f); 
        echo "Memory profile dumped. "; 
    } 
    

    W moim przypadku był w dużym cyklu co 100 biegów.

  5. Run google-pprof porównując 2 zrzutów pamięci:

    google-pprof --web --base=/tmp/profile_17.heap /tmp/profile_18.heap 
    

    To otworzy obraz SVG takiego w przeglądarce:

    sample from doc

    Opis numerów i nazw wewnątrz można znaleźć w gperftools documentation

P.S. Naprawianie nieszczelności na poziomie php nie gwarantuje, że nie ma wycieków pamięci w interpretera. W moim przypadku kończę właśnie z ponownym uruchomieniem sctipt w dłuższych okresach.

+0

Jak to naprawić? 'Nie można uzyskać liczby symboli od http: /// pprof/symbol' – user2264941

Powiązane problemy