PHP - ошибка исчерпания памяти, случайно возникающая на рабочем сервере - PullRequest
2 голосов
/ 23 января 2020

Я случайно (около 20 раз в день) получаю эту ошибку на рабочем сервере (PHP 7.0.32):

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

«Наличие» ошибки довольно низкое, поэтому далеко, но поскольку я не уверен, что не так, меня беспокоит будущее и большие проблемы.

Я запускаю этот код вверху страницы, когда возникает ошибка:

    $curTime = time();
    $dataIds = array("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");

    $end = array();
    $update = array();
    $dbUpdate = array();

    foreach($dataIds as $id) {
        $f = fopen( "./data/{$id}.json", "r");
        if ($f === false) {
            continue;
        }

        $data = fread($f, 1024);
        fclose($f);
        $data = json_decode($data, true);

        if (!isset($data['input'])) {
            continue;
        }

        $endDate = $data['input'][0]['end'];
        $updateDate = $data['input'][0]['start'];
        $dbUpdateDate = $data['input'][0]['update'];

        $end[$id] = ($endDate !== "") ? strtotime($endDate." UTC") : $curTime;
        $update[$id] = ($updateDate !== "") ? strtotime($updateDate." UTC") : $curTime;
        $dbUpdate[$id] = ($dbUpdateDate !== "") ? strtotime($dbUpdateDate." UTC") : $curTime;
    }

И в этой строке выдается ошибка:

 $end[$id] = ($endDate !== "") ? strtotime($endDate." UTC") : $curTime;

Я не могу воспроизвести проблему с сервером разработки, и я не уверен, что может вызвать это и как это отладить (я не могу включить функции отладки на производственном сервере). Других предупреждений или уведомлений до неустранимой ошибки нет.

Файлы данных json имеют небольшой размер, около 500 байт. Они, однако, обновляются с задания cron. Так что теоретически я могу открыть неполный файл. Но в этом случае json_decode возвращает null, как я тестировал.

Образец json:

{
    "input":    [{
            "id":   "1",
            "start":    "2019-11-15 06:00:00",
            "end":  "2019-11-18 12:00:00",
            "update":   "2019-11-15 10:52:44"
        }]
}

Ответы [ 3 ]

2 голосов
/ 23 января 2020

Это единственное разумное объяснение, которое я могу придумать, пожалуйста, проверьте, верны ли мои выводы.

Ваши $dataIds - это не маленькие целые числа, а миллиарды в вашем реальном коде. По какой-то причине, PHP, похоже, $this->end напечатан как строка, а не как массив. По сути, вы делаете это:

$stuff='string';
$stuff[5000000000]='y'; // will allocate 5 GB of RAM, exceeding your 128M maximum 

когда вы думаете вы делаете это:

$stuff=new Array();
$stuff[5000000000]='y'; // will allocate just a few Bytes since it is an asssociative Array

Вам придется копаться в других ваших частях кода, чтобы понять, почему это может иметь место

1 голос
/ 01 февраля 2020

Немного потрудившись (см. другой ответ , который начался с совершенно другой касательной), кажется, что огромное выделение памяти более 4 ГБ ОЗУ происходит внутри strtotime. Неясно, связано ли это с PHP ошибка # 53502 (это старая ошибка PHP 5.3, в настоящее время помечена как закрытая) или нет.

Однако, изменение

$end[$id] = ($endDate !== "") ? strtotime($endDate." UTC") : $curTime;

до

date_default_timezone_set("UTC");
$end[$id] = ($endDate !== "") ? strtotime($endDate) : $curTime;

избавляется от явления и работает плавно. В настоящее время неясно, является ли какое-либо конкретное c значение $endDate причиной этого или что еще может быть способствующим фактором.

0 голосов
/ 23 января 2020

Вы можете добавить это ниже в свой скрипт (поместите его в самый верх)

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

, позже вы можете установить -1 на что-то вроде 256, если у вас было 64 или что-то еще меньше, чего было недостаточно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...