Mam kilka systemów POS, które okresowo wysyłają nowe dane sprzedażowe do jednej scentralizowanej bazy danych, która przechowuje dane w jednej dużej bazie danych w celu generowania raportów.
Klient POS oparty jest na PHPPOS, a ja wdrożyłem moduł, który używa standardowej biblioteki XML-RPC do wysyłania danych sprzedaży do usługi. System serwera jest zbudowany na CodeIgniter i wykorzystuje biblioteki XML-RPC i XML-RPCS dla komponentu webservice. Ilekroć wysyłam dużo danych dotyczących sprzedaży (zaledwie 50 wierszy z tabeli sprzedaży i poszczególnych wierszy z elementów_ sprzedaży dotyczących każdego elementu w sprzedaży), pojawia się następujący błąd:
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 54 bytes)
128M jest wartością domyślną php.ini
, ale zakładam, że jest to ogromna liczba do złamania. W rzeczywistości próbowałem nawet ustawić tę wartość na 1024 M, a wszystko, co robi, zajmuje więcej czasu, aby się pomylić.
Jeśli chodzi o kroki, które podjąłem, próbowałem wyłączyć wszystkie przetwarzanie po stronie serwera i przygotowałem je tak, aby zwróciło pełną odpowiedź niezależnie od danych wejściowych. Uważam jednak, że problem polega na faktycznym wysłaniu danych. Próbowałem nawet wyłączyć maksymalny czas wykonywania skryptu dla PHP i nadal występuje błąd.
źródło
ini_set('memory_limit', '256M');
Odpowiedzi:
Zmiana
memory_limit
Byini_set('memory_limit', '-1');
to nie właściwe rozwiązanie. Proszę nie rób tego.Twój kod PHP może mieć gdzieś wyciek pamięci i mówisz serwerowi, aby używał całej pamięci, którą chce. W ogóle nie naprawiłbyś problemu. Jeśli monitorujesz serwer, zobaczysz, że prawdopodobnie zużywa on większość pamięci RAM, a nawet zamienia na dysk.
Prawdopodobnie powinieneś spróbować wyśledzić obrażający kod w swoim kodzie i go naprawić.
źródło
-1
może być użyteczna tylko w środowiskach programistycznych do celów testowych.ini_set('memory_limit', '-1');
zastępuje domyślny limit pamięci PHP .źródło
-1
jest wartością, którą PHP rozumie jako nieograniczoną w tym kontekście.Prawidłowym sposobem jest edycja
php.ini
pliku. Edytujmemory_limit
do pożądanej wartości.Od twojego pytania
128M
(który jest domyślnym limitem) zostało przekroczone, więc jest coś poważnie nie tak z twoim kodem, ponieważ nie powinien on zabierać tak dużo.Jeśli wiesz, dlaczego to tyle zajmuje, i chcesz pozwolić, by ustawiono go
memory_limit = 512M
wyżej lub wyżej i powinieneś być dobry.źródło
Przydział pamięci dla PHP można zmienić na stałe lub tymczasowo.
Na stałe
Możesz trwale zmienić przydział pamięci PHP na dwa sposoby.
Jeśli masz dostęp do swojego
php.ini
pliku, możesz edytować wartość dlamemory_limit
żądanej wartości.Jeśli nie masz dostępu do swojego
php.ini
pliku (a webhost na to pozwala), możesz zastąpić przydział pamięci za pomocą swojego.htaccess
pliku. Dodajphp_value memory_limit 128M
(lub cokolwiek chcesz).Chwilowy
Możesz dostosować przydział pamięci w locie z poziomu pliku PHP. Po prostu masz kod
ini_set('memory_limit', '128M');
(lub jakikolwiek inny pożądany przydział). Możesz usunąć limit pamięci (chociaż limity komputera lub instancji mogą nadal obowiązywać), ustawiając wartość na „-1”.źródło
Bardzo łatwo jest uzyskać wycieki pamięci w skrypcie PHP - szczególnie jeśli używasz abstrakcji, takiej jak ORM. Spróbuj użyć Xdebug do profilowania skryptu i dowiedz się, dokąd poszła cała ta pamięć.
źródło
Dodając 22,5 miliona rekordów do tablicy za pomocą array_push, ciągle dochodziło do „wyczerpania pamięci” krytycznych błędów przy około 20 milionach rekordów, wykorzystując
4G
jako limit pamięci w pliku php.ini. Aby to naprawić, dodałem oświadczenieu góry pliku. Teraz wszystko działa dobrze. Nie wiem, czy PHP ma wyciek pamięci. To nie jest moja praca, nie obchodzi mnie to. Muszę tylko wykonać swoją pracę i to zadziałało.
Program jest bardzo prosty:
Błąd krytyczny wskazuje na linię 3, dopóki nie zwiększyłem limitu pamięci, co wyeliminowało błąd.
źródło
ini_set('memory_limit', '8192M');
?Wciąż otrzymywałem ten błąd, nawet po
memory_limit
ustawieniuphp.ini
, a wartość poprawnie odczytywana za pomocąphpinfo()
.Zmieniając to z tego:
Do tego:
To rozwiązało problem w PHP 7.
źródło
Gdy zobaczysz powyższy błąd - zwłaszcza jeśli
(tried to allocate __ bytes)
jest to niska wartość, może to być wskaźnik nieskończonej pętli, jak funkcja, która wywołuje się bez wyjścia:źródło
Po włączeniu tych dwóch linii zaczął działać:
źródło
Możesz to naprawić, zmieniając
memory_limit
na fastcgi / fpm:Zmień pamięć, na przykład z 128 na 512, patrz poniżej
do
źródło
Katalog główny Twojej witryny:
źródło
Zmień limit pamięci w pliku php.ini i zrestartuj Apache. Po ponownym uruchomieniu uruchom phpinfo (); funkcja z dowolnego pliku PHP w celu
memory_limit
potwierdzenia zmiany.Limit pamięci -1 oznacza, że nie ma ustawionego limitu pamięci. Teraz jest na maksimum.
źródło
Dla użytkowników Drupala odpowiedź Chrisa Lane'a na:
działa, ale musimy go umieścić tuż po otwarciu
znacznik w pliku index.php w katalogu głównym witryny.
źródło
W Drupal 7 możesz modyfikować limit pamięci w pliku settings.php znajdującym się w twoim folderze strony / domyślny. Wokół linii 260 zobaczysz to:
Nawet jeśli twoje ustawienia php.ini są wystarczająco wysokie, nie będziesz w stanie zużyć więcej niż 128 MB, jeśli nie jest to ustawione w pliku Drupal settings.php.
źródło
Zamiast zmieniać
memory_limit
wartość wphp.ini
pliku, jeśli jest część kodu, która mogłaby zużyć dużo pamięci, możesz usunąćmemory_limit
przed uruchomieniem tej sekcji, a następnie zastąpić ją później.źródło
PHP 5.3+ pozwala zmienić limit pamięci poprzez umieszczenie
.user.ini
pliku wpublic_html
folderze. Po prostu utwórz powyższy plik i wpisz w nim następujący wiersz:Niektóre hosty cPanel akceptują tylko tę metodę.
źródło
Awaria strony?
(Dzieje się tak, gdy MySQL musi wyszukiwać duże wiersze. Domyślnie
memory_limit
jest ustawiony na mały, co było bezpieczniejsze dla sprzętu.)Możesz sprawdzić status pamięci w systemie, zanim zwiększysz
php.ini
:Tutaj zwiększyłem go, jak poniżej, a następnie zrobiłem,
service httpd restart
aby naprawić problem ze stroną awarii.źródło
free -m
polecenia, aby zdecydować o nowym limicie pamięci?Po prostu dodaj
ini_set('memory_limit', '-1');
wiersz u góry strony internetowej.I możesz ustawić swoją pamięć według potrzeb zamiast -1
16M
, itd.źródło
Dla tych, którzy drapią się po głowie, aby dowiedzieć się, dlaczego na ziemi ta mała funkcja powinna powodować wyciek pamięci, czasem przez pomyłkę, funkcja zaczyna się nazywać rekurencyjnie na zawsze.
Na przykład klasa proxy, która ma taką samą nazwę dla funkcji obiektu, który będzie ją proxy.
Czasami możesz zapomnieć o zabraniu tego małego faktycznego członkaObjec, a ponieważ proxy ma taką
doSomething
metodę, PHP nie dałoby ci żadnego błędu, a dla dużej klasy można go ukryć przed oczami na kilka minut, aby dowiedzieć się, dlaczego przecieka pamięć.źródło
die('here')
kod i przesunąć tę instrukcję, aby zobaczyć, gdzie zaczyna się rekurencja.Wystąpił błąd poniżej podczas pracy na zestawie danych mniejszym niż wcześniej działał.
Gdy przyniosło mi to poszukiwanie winy, pomyślałem, że wspomnę, że nie zawsze są to rozwiązania techniczne z poprzednich odpowiedzi, ale coś prostszego. W moim przypadku był to Firefox. Przed uruchomieniem program zużywał już 1157 MB.
Okazuje się, że przez kilka dni oglądałem po 50 minut wideo po trochu i to wszystko popsuło. Jest to rodzaj poprawki, którą eksperci poprawiają, nawet o tym nie myśląc, ale dla takich jak ja warto o tym pamiętać.
źródło
Uruchomienie takiego skryptu (na przykład przypadek cron):
php5 /pathToScript/info.php
powoduje ten sam błąd.Prawidłowy sposób:
php5 -cli /pathToScript/info.php
źródło
Jeśli korzystasz z VPS (wirtualnego prywatnego serwera) zasilanego przez WHM, może się okazać, że nie masz uprawnień do bezpośredniej edycji PHP.INI; system musi to zrobić. W panelu sterowania hosta WHM przejdź do Konfiguracja usługi → Edytor konfiguracji PHP i zmodyfikuj
memory_limit
:źródło
Uważam, że jest to przydatne, gdy dołączam lub wymagam
_dbconnection.php_
oraz_functions.php
w faktycznie przetwarzanych plikach, a nie w nagłówku. Który jest zawarty w sobie.Jeśli więc uwzględniono nagłówek i stopkę , po prostu dołącz wszystkie pliki funkcjonalne przed dołączeniem nagłówka.
źródło
Używanie
yield
może być również rozwiązaniem. Zobacz składnię generatora .Zamiast zmieniać
PHP.ini
plik na większą pamięć, czasem zaimplementowanieyield
wewnętrznej pętli może rozwiązać problem. Wydajność polega na tym, że zamiast zrzucać wszystkie dane naraz, odczytuje je jeden po drugim, oszczędzając dużo pamięci.źródło
PHP.ini
? Nie jest tophp.ini
?Ten błąd jest czasami spowodowany błędem w kodzie PHP, który powoduje rekurencje związane z obsługą wyjątków i ewentualnie innymi operacjami. Niestety nie udało mi się stworzyć małego przykładu.
W tych przypadkach, które zdarzyły mi się kilka razy,
set_time_limit
kończy się niepowodzeniem, a przeglądarka próbuje załadować dane wyjściowe PHP, albo za pomocą nieskończonej pętli, albo za pomocą fatalnego komunikatu o błędzie, który jest tematem tego pytania.Poprzez zmniejszenie dozwolonego rozmiaru alokacji poprzez dodanie
na początku kodu powinieneś być w stanie zapobiec błędowi krytycznemu.
Wtedy możesz zostać z programem, który się kończy, ale nadal jest trudny do debugowania.
W tym momencie wstaw
BreakLoop()
wywołania do swojego programu, aby przejąć kontrolę i dowiedzieć się, która pętla lub rekurencja w twoim programie powoduje problem.Definicja BreakLoop jest następująca:
Argument $ LoopSite może być nazwą funkcji w kodzie. Nie jest to naprawdę konieczne, ponieważ komunikat o błędzie, który otrzymasz, wskaże Ci wiersz zawierający wywołanie BreakLoop ().
źródło
W moim przypadku był to krótki problem ze sposobem napisania funkcji. Wyciek pamięci może być spowodowany przez przypisanie nowej wartości do zmiennej wejściowej funkcji, np .:
źródło
Kiedy usunąłem następujące wiersze z mojego kodu, wszystko działało OK!
Te linie były zawarte w każdym pliku, który uruchomiłem. Podczas uruchamiania plików jeden po drugim wszystko działało OK, ale podczas uruchamiania wszystkich plików wystąpił problem z wyciekiem pamięci. Jakoś „include_once” nie obejmuje rzeczy raz, lub robię coś złego…
źródło
set_include_path(get_include_path() . get_include_path().'/phpseclib');
Spowoduje to dodanie ścieżki „/ phpseclib” jeden raz dla każdego pliku, który ma linię ... dzięki czemu może dodać ją wiele razy! Sugeruję umieszczenie go w pliku ustawień iinclude_once
pliku ustawień.