Фатальна помилка: Дозволений розмір пам'яті 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.