Фатальна помилка: Дозволений розмір пам'яті 134217728 вичерпаних байтів (CodeIgniter + XML-RPC)


618

У мене є купа систем продажу клієнтів (POS), які періодично надсилають нові дані продажів в одну централізовану базу даних, яка зберігає дані в одну велику базу даних для формування звітів.

POS клієнта базується на PHPPOS, і я реалізував модуль, який використовує стандартну бібліотеку XML-RPC для надсилання даних про продаж в сервіс. Серверна система побудована на CodeIgniter і використовує бібліотеки XML-RPC та XML-RPCS для компонента веб-сервісу. Щоразу, коли я надсилаю багато даних про продажі (всього 50 рядків із таблиці продажів та окремих рядків з Sales_items, що стосуються кожного товару в рамках продажу), я отримую таку помилку:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 54 bytes)

128M - це значення за замовчуванням у php.ini, але я припускаю, що це величезна кількість, яку потрібно зламати. Насправді я навіть спробував встановити це значення у 1024М, і все, що він робить, потребує більш тривалого часу, щоб виправити помилки.

Щодо кроків, які я вжив, я намагався відключити всю обробку на стороні сервера і сфабрикував її, щоб повернути консервовану відповідь незалежно від вводу. Однак я вважаю, що проблема полягає у фактичному надсиланні даних. Я навіть намагався відключити максимальний час виконання скрипту для PHP, і він все ще помиляється.


5
Я трохи розгублений ... де трапляється помилка - у клієнта чи сервера? І на якому етапі ... відправлення клієнта, отримання сервера, обробка сервера, надсилання сервера, отримання клієнта або обробка клієнта?
Грег

2
Здається, помилка виникає або під час надсилання клієнта, або при отриманні сервера. Я намагався відключити всю обробку на сервері та сфабрикував її для надсилання консервованої відповіді незалежно від надісланих даних. Помилка виникає, якщо я надсилаю певний обсяг даних. Я змінюю налаштування PHP.ini
ArcticZero

42
Ліміт пам’яті - 128 Мб, суббл:ini_set('memory_limit', '256M');

9
Короткий зміст оголосив усі відповіді "просто ігноруйте витік", людей, які плутали CodeIgniter з Drupal та людей, які просто копіюють та вставляють відповіді інших людей, щоб отримати бали. Якість відповідей у ​​цьому - ненормальна.
Матті Вірккунен

Відповіді:


697

Зміна memory_limitУ ini_set('memory_limit', '-1');є НЕ правильним рішенням. Будь ласка, не робіть цього.

У вашому PHP-коді може десь витікати пам'ять, і ви говорите серверу просто використовувати всю потрібну пам'ять. Ви б зовсім не виправили проблему. Якщо ви стежите за своїм сервером, ви побачите, що він, ймовірно, використовує більшу частину оперативної пам’яті і навіть переходить на диск.

Вам, мабуть, слід спробувати відстежити в коді правопорушення та виправити його.


173
@Jeff Ви, напевно, маєте рацію в 95% часу. Однак бувають випадки, коли вам справді потрібно більше пам’яті. Наприклад, скажімо, що ваш додаток завантажує величезну кількість даних у пам'ять для обробки (скажімо, законопроект із 15-ти компонентними компонентами) Не завжди буває так, що код баггі, іноді потрібно просто трохи більше пам’яті (наприклад, 256 М замість 128 М). Однак я згоден, що встановити його на -1 - жахливо погано. Але налаштування межі пам’яті для розумних ситуацій під час роботи є цілком прийнятним рішенням.
Пірит

24
@pyrite та ви маєте рацію , що іноді процес вимагає більше пам'яті , але ви повинні збільшити обсяг пам'яті до деякої логічної суми , як 256 МБ , як ви сказали , чи 512 Мб , чому немає , але не -1;)
Lukas Lukac

9
@jeff Я повністю згоден, значення -1може бути корисним лише для розробників у тестових цілях.
Езолітос

4
@ Пишіть у випадках, яких ви назвали для інших 5%, читайте дані шматками та використовуйте працівника для їх обробки, а не більше пам'яті. Це рішення також буде масштабуватися, поки ваші пропозиції не працюватимуть, за винятком того, що з часом зростатимуть все більше пам’яті на ваш сервер, якщо дані будуть рости.
бурзум

2
Найчастіше ця проблема в ORM, коли ви намагаєтеся отримати всі дані, які значно більше обмежують PHP. Наприклад, коли ви намагаєтеся генерувати щомісячний звіт.
Степчик

213

ini_set('memory_limit', '-1');перевищує стандартний ліміт пам'яті PHP .


16
@williamcarswell; -1це значення, яке PHP розуміє як необмежене в цьому контексті.
Алікс Аксель

7
@ ArseniuszŁozicki - він також споживатиме ресурси, які сервер не може шкодувати.
Кен Вільямс

124
Ганьба, що за це отримують так багато відгуків. Встановлення його в точному значенні, або з редакціями php.ini, або з ini_set, - цілком правильне рішення, коли людям потрібно більше пам’яті. Встановити його необмежено - це небезпечний злом :(
Джефф Девіс

24
@ user1767586 тоді встановіть його на здорове значення. Ви можете запобігти видаленню помилки сценарію, встановивши його на 1024M. Якщо ця відповідь сказала ini_set ('memory_limit', '1024M'); Ви можете скопіювати це і вставити. Встановивши його на -1, ви налаштовуєте себе на те, щоб мати сценарій, який забирає всю пам'ять. Особливо, якщо ви робите це рутинно. Внесення «небезпечних» у лапки не робить його менш небезпечним. Ви дійсно можете ввести шланг свого хост-сервера. Можливо, почніть знищувати дані. Я не знаю, може, втратите роботу? Звучить для мене досить небезпечно. : |
Джефф Девіс

3
Сумно бачити, що відповідь за +161 голос і -3 голоси однакова :(
akarthik10

130

Правильний спосіб - це редагувати php.iniфайл. Відредагуйте memory_limitза вашим бажанням значення.

Оскільки ваше запитання 128M(яке є лімітом за замовчуванням) було перевищено, тож у вашому коді щось серйозно не так, оскільки він не повинен займати стільки.

Якщо ви знаєте, чому це забирає стільки, і ви хочете дозволити йому встановити memory_limit = 512Mчи вище, і ви повинні бути хорошими.


7
Чесно кажучи, якщо ви кешуєте серйозні обсяги даних, це правильна відповідь. 128М недостатньо для певних сценаріїв. 512M або 1024M часто буде достатньо, але вам доведеться вирішувати в кожному випадку.
Джефф Девіс

2
Yeha, проте намагайтеся уникати величезного використання пам'яті, якщо кількість користувачів буде більшою
Basav

2
memory_limit = -1; встановити в php.ini

2
@YumYumYum Це видаляє memory_limit, який ви хочете, лише якщо ви контролюєте використання пам'яті іншим способом. ОС буде вбивати процес, якщо він займає величезну кількість пам'яті в якийсь момент будь-яким способом.
Flimm

Отже, якщо ви використовуєте скрипт, який використовує багато пам’яті, але його потрібно запустити лише один раз, чи можете ви просто збільшити ліміт пам’яті для процесу на момент виконання, а потім знизити ліміт пам’яті після одноразового використання сценарій працює?
chromechris

95

Виділення пам'яті для PHP може бути відрегульовано постійно або тимчасово.

Постійно

Ви можете назавжди змінити розподіл пам'яті PHP двома способами.

Якщо у вас є доступ до вашого php.iniфайлу, ви можете відредагувати значення для memory_limitвашого бажання.

Якщо у вас немає доступу до вашого php.iniфайлу (а ваш веб-хост дозволяє), ви можете змінити розподіл пам'яті через ваш .htaccessфайл. Додайте php_value memory_limit 128M(або все, що потрібно).

Тимчасовий

Ви можете налаштувати розподіл пам’яті під час руху з файлу PHP. У вас просто є код ini_set('memory_limit', '128M');(або все, що вам потрібно). Ви можете зняти ліміт пам’яті (хоча обмеження на машину чи примірник все ще можуть застосовуватися), встановивши значення «-1».


2
Дякую, я не думав перевіряти, чи хтось встановив значення у .htaccess, який переважав php.ini, і я не міг зрозуміти, чому +1
HostMyBus

61

Дуже легко отримати витоки пам'яті в PHP-скрипті - особливо якщо ви використовуєте абстракцію, наприклад ORM. Спробуйте використовувати Xdebug для профілю свого сценарію та дізнайтеся, куди поділася вся ця пам’ять.


1
Я піду спробувати Xdebug. Я ніколи не використовував її раніше, тому мені доведеться її читати. Дякую за відповідь! Сподіваюся, що я скоро знайду відповідь на це ...
ArcticZero

34
Пам'ятайте, що PHP використовує підрахунок посилань для управління пам'яттю. Отже, якщо у вас є кругові посилання або глобальні змінні, ці об’єкти не підлягають вторинній переробці. Зазвичай корінь пам'яті протікає в PHP.
troelskn

Xdebug показує, що бібліотека CI Xmlrpc.php відповідає за витік моєї пам'яті. Чи випадково виникнуть проблеми з бібліотеками XML-RPC RPC CodeIgniter, про які я повинен знати? Я спробував відключити всю обробку на стороні сервера, і у неї все ще не вистачає пам'яті, якщо я подаю їй достатньо даних.
ArcticZero

1
Я не знаю / не використовую CI, тому не знаю. Але вам, мабуть, слід спробувати знайти об’єкт, який не буде звільнений після використання - швидше за все, через циклічне посилання. Це детективна робота.
troelskn

1
Це єдина відповідь, яка радить реально вирішити проблему. Інші відповіді розширюють пам’ять, щоб перев’язати симптом і ігнорувати захворювання .
Кріс Бейкер

56

Додаючи 22,5 мільйона записів у масив з array_push, я продовжував отримувати "виснажену пам'ять" фатальні помилки біля 20 М записів, використовуючи 4Gяк обмеження пам'яті у файлі php.ini. Щоб виправити це, я додав заяву

$old = ini_set('memory_limit', '8192M');

у верхній частині файлу. Зараз все працює нормально. Я не знаю, чи є в PHP витік пам'яті. Це не моя робота, і мене це не хвилює. Мені просто потрібно виконати свою роботу, і це спрацювало.

Програма дуже проста:

$fh = fopen($myfile);
while (!feof($fh)) {
    array_push($file, stripslashes(fgets($fh)));
}
fclose($fh);

Фатальна помилка вказує на рядок 3, поки я не збільшив межу пам'яті, що усунула помилку.


10
ти маєш на увазі ini_set('memory_limit', '8192M');?
Гоголь

2
Яка розкіш було б встигнути поїхати та оптимізувати сценарій для чогось подібного. Або досліджуйте та порівнюйте та вивчайте інструменти ETL чи щось подібне. У реальному світі ми піднімаємо запас пам’яті вгору, робимо це та рухаємось далі.
Метью Поер

45

Я продовжував отримувати цю помилку, навіть якщо memory_limitвстановлено php.ini, і значення, прочитане правильно, з phpinfo().

Змінивши це з цього:

memory_limit=4G

До цього:

memory_limit=4096M

Це усунуло проблему в PHP 7.


23

Коли ви бачите вищезгадану помилку - особливо якщо (tried to allocate __ bytes)значення низьке, це може бути показником нескінченного циклу, як функція, яка викликає себе без виходу:

function exhaustYourBytes()
{
    return exhaustYourBytes();
}

19

Після ввімкнення цих двох рядків він почав працювати:

; Determines the size of the realpath cache to be used by PHP. This value should
; be increased on systems where PHP opens many files to reflect the quantity of
; the file operations performed.
; http://php.net/realpath-cache-size
realpath_cache_size = 16k

; Duration of time, in seconds for which to cache realpath information for a given
; file or directory. For systems with rarely changing files, consider increasing this
; value.
; http://php.net/realpath-cache-ttl
realpath_cache_ttl = 120


19

Ви можете правильно виправити це, змінивши режим memory_limitfastcgi / fpm:

$vim /etc/php5/fpm/php.ini

Змінення пам’яті, наприклад, від 128 до 512, див. Нижче

; Maximum amount of memory a script may consume (128 MB)
; http://php.net/memory-limit
memory_limit = 128M

до

; Maximum amount of memory a script may consume (128 MB)
; http://php.net/memory-limit
memory_limit = 512M

18

Кореневий каталог вашого веб-сайту:

ini_set('memory_limit', '1024M');

1
це працювало для мене. люблю одну лінію рішень. +1 для простоти
Стів C

14

Змініть ліміт пам'яті у файлі php.ini та перезапустіть Apache. Після перезапуску запустіть phpinfo (); функція з будь-якого файлу PHP для memory_limitпідтвердження зміни.

memory_limit = -1

Ліміт пам’яті -1 означає, що обмеження пам'яті не встановлено. Зараз це на максимумі.


13

Для користувачів Drupal ця відповідь Кріса Лейн:

ini_set('memory_limit', '-1');

працює, але нам потрібно поставити його відразу після відкриття

<?php

тег у файлі index.php у кореневому каталозі вашого сайту.


13

У Drupal 7 ви можете змінити ліміт пам’яті у файлі settings.php, що знаходиться у вашій папці сайтів / за замовчуванням. Приблизно в рядку 260 ви побачите це:

ini_set('memory_limit', '128M');

Навіть якщо ваші налаштування php.ini досить високі, ви не зможете споживати більше 128 Мб, якщо це не встановлено у вашому файлі Drupal settings.php.


1
Не в Drupal7 немає такого рядка коду в settings.php
FLY

Також немає стрій у settings.php для drupal 6
AllisonC

12

Замість того, щоб змінювати memory_limitзначення у вашому php.iniфайлі, якщо є частина вашого коду, яка може зайняти багато пам'яті, ви можете видалити memory_limitдо запуску цього розділу, а потім замінити його після.

$limit = ini_get('memory_limit');
ini_set('memory_limit', -1);
// ... do heavy stuff
ini_set('memory_limit', $limit);

7

PHP 5.3+ дозволяє змінити ліміт пам'яті, помістивши .user.iniфайл у public_htmlпапку. Просто створіть вищезазначений файл і введіть у ньому наступний рядок:

memory_limit = 64M

Деякі хости cPanel приймають лише цей метод.


7

Сторінка збоїв?

Введіть тут опис зображення

(Це трапляється, коли MySQL має запитувати великі рядки. За замовчуванням memory_limitвстановлюється малий, що було безпечніше для обладнання.)

Ви можете перевірити наявний стан вашої системи перед тим, як збільшити php.ini:

# free -m
             total       used       free     shared    buffers     cached
Mem:         64457      63791        666          0       1118      18273
-/+ buffers/cache:      44398      20058
Swap:         1021          0       1021

Тут я збільшив його, як у наступному, а потім зробити, service httpd restartщоб виправити проблему зі збоєм.

# grep memory_limit /etc/php.ini
memory_limit = 512M

Яке число (рядок і стовпець?) Слід переглянути після запуску free -mкоманди, щоб визначитися з новим обмеженням пам'яті?
kiradotee

7

Просто додайте ini_set('memory_limit', '-1');рядок у верхній частині веб-сторінки.

І ви можете встановити пам'ять відповідно до ваших потреб замість -1, до 16Mтощо.


6
Здається, це говорить те саме, що і багато існуючих відповідей. Краще лише додати відповідь на популярне запитання, лише якщо новий матеріал пропонує щось нове.
половина

6

Для тих, хто чухає голову, щоб дізнатися, чому на землі ця маленька функція повинна спричинити протікання пам’яті, іноді невеликою помилкою, функція починає рекурсивно називати себе назавжди.

Наприклад, клас проксі-сервера, який має те саме ім’я для функції об’єкта, який збирається проксі.

class Proxy {

    private $actualObject;

    public function doSomething() {

        return $this->actualObjec->doSomething();
    }
}

Іноді ви можете забути принести цього маленького фактичного члена OObc, і оскільки проксі насправді має цей doSomethingметод, PHP не дасть вам помилок, і для великого класу це може бути приховано від очей на пару хвилин, щоб дізнатися, чому це просочується пам'ять.


І ще одна порада: ви можете ввести die('here')свій код і перемістити цей оператор навколо, щоб побачити, звідки починається рекурсія.
Тоддмо

6

У мене була помилка нижче під час роботи на наборі даних менше, ніж працювали раніше.

Фатальна помилка: Дозволений розмір пам'яті 134217728 байтів вичерпано (намагався виділити 4096 байт) у C: \ workpace \ image_management.php у рядку 173

Оскільки пошук вини привів мене сюди, я подумав зазначити, що це не завжди технічні рішення в попередніх відповідях, а щось більш просте. У моєму випадку це був Firefox. Перед тим, як запустити програму, вона вже використовувала 1,157 Мб.

Виявляється, я переглядав 50-хвилинне відео трохи за раз протягом кількох днів, і це зіпсувало речі. Це виправлення, яке виправляють експерти, навіть не замислюючись над цим, але для мене подібних варто пам’ятати.


У Google Chrome сьогодні було подібне явище. Я вкрай скептично ставився до цієї відповіді ... однак, це виявило, що моє байтове виснаження зникло після того, як я відкрив вікно анонімного перегляду і знову запустив той самий сценарій! Дослідження тривають.
mickmackusa

2

Запуск сценарію, подібного до цього (наприклад, у випадку із cron): php5 /pathToScript/info.phpвидає ту ж помилку

Правильний спосіб: php5 -cli /pathToScript/info.php


2

Якщо у вас працює VPS на основі WHM (віртуального приватного сервера), ви можете виявити, що у вас немає дозволів безпосередньо редагувати PHP.INI; система повинна це робити. На панелі керування хосту WHM перейдіть до Конфігурація службиРедактор конфігурації PHP та змініть memory_limit:

Оновлення memory_limit у WHM 11.48.4


2

Я вважаю це корисним при включенні або вимоги _dbconnection.php_і _functions.phpв файлах, які фактично обробляється, а не в тому числі в заголовку. Що входить в себе.

Отже, якщо ваш заголовок і колонтитул включені, просто включіть всі свої функціональні файли до того, як буде заголовок.


2

Використання також yieldможе бути рішенням. Див. Синтаксис генератора .

Замість того, щоб змінити PHP.iniфайл для збільшення пам’яті, іноді реалізація yieldвсередині циклу може вирішити проблему. Прибутковість - це замість того, щоб скидати всі дані одразу, вони читають їх по черзі, економлячи багато використання пам'яті.


2
PHP.ini? Чи не так php.ini?
Пітер Мортенсен

1

Ця помилка іноді викликається помилкою в коді PHP, яка викликає рекурсії, пов'язані з обробкою виключень і, можливо, іншими операціями. На жаль, мені не вдалося створити крихітний приклад.

У цих випадках, які траплялися зі мною декілька разів, set_time_limitне виходить, і браузер намагається завантажувати вихід PHP або нескінченним циклом, або повідомленням про фатальну помилку, що є темою цього питання.

За рахунок зменшення дозволеного розміру виділення додаванням

ini_set('memory_limit','1M');

біля початку коду ви повинні мати можливість запобігти фатальній помилці.

Тоді вам може залишитися з програмою, яка припиняється, але це все ще важко налагодити.

У цей момент вставте BreakLoop()виклики всередині програми, щоб отримати контроль і з’ясувати, який цикл або рекурсія у вашій програмі викликає проблему.

Визначення BreakLoop таке:

function BreakLoop($MaxRepetitions=500,$LoopSite="unspecified")
    {
    static $Sites=[];
    if (!@$Sites[$LoopSite] || !$MaxRepetitions)
        $Sites[$LoopSite]=['n'=>0, 'if'=>0];
    if (!$MaxRepetitions)
        return;
    if (++$Sites[$LoopSite]['n'] >= $MaxRepetitions)
        {
        $S=debug_backtrace(); // array_reverse
        $info=$S[0];
        $File=$info['file'];
        $Line=$info['line'];
        exit("*** Loop for site $LoopSite was interrupted after $MaxRepetitions repetitions. In file $File at line $Line.");
        }
    } // BreakLoop

Аргумент $ LoopSite може бути назвою функції у вашому коді. Це насправді не потрібно, оскільки повідомлення про помилку, яке ви отримаєте, вкаже на лінію, що містить виклик BreakLoop ().


-1

У моєму випадку це було коротке питання про те, як була написана функція. Витік пам'яті може бути викликано присвоєнням нового значення вхідній змінній функції, наприклад:

/**
* Memory leak function that illustrates unintentional bad code
* @param $variable - input function that will be assigned a new value
* @return null
**/
function doSomehting($variable){
    $variable = 'set value';
    // Or
    $variable .= 'set value';
}

-6

Коли я видалив наступні рядки зі свого коду, все працювало нормально!

set_include_path(get_include_path() . get_include_path() . '/phpseclib');
include_once('Net/SSH2.php');
include_once('Net/SFTP.php');

Ці рядки були включені до кожного файлу, який я працював. Під час роботи файлів по черзі все працювало нормально, але при запуску всіх файлів разом у мене виникла проблема витоку пам'яті. Якось "include_once" не включає речі один раз, або я щось неправильно роблю ...


set_include_path(get_include_path() . get_include_path().'/phpseclib'); Це додасть шлях '/ phpseclib' один раз для кожного файлу, що має рядок ... так що він може додавати його багато разів! Я б запропонував помістити його у файл налаштувань та include_onceфайл налаштувань.
Farfromunique
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.