Сборщик мусора PHP не работает?

У меня есть приложение на основе Laravel, которое работает поверх php 7.0

У меня проблема с работниками очереди php artisan queue:work --daemon в том смысле, что он со временем потребляет память.

Базовый код, который начинает обработку, выглядит так (показана только важная часть)

<?php

namespace App\Jobs;

class TaskCronJoib extends Job implements ShouldQueue
{
   use InteractsWithQueue, SerializesModels;

   private $type;

   public function __construct(string $type)
   {
      $this->type = $type;
   }

    public function handle()
    {
        $handler = app()->make(HandlerFactory::class)->get($this->type);
        $handler->process();
    }
}

Я тестировал (и это работает), что когда я добавляю gc_collect_cycles () в конце handle(), со временем он потребляет гораздо меньше памяти.

Как это

Я тестировал (и это работает), что когда я добавляю gc_collect_cycles () в конце handle(), со временем он потребляет гораздо меньше памяти.

    public function handle()
    {
        $handler = app()->make(HandlerFactory::class)->get($this->type);
        $handler->process();
        gc_collect_cycles();
    }

Рабочие Laravel работают бесконечно, поэтому это обычный случай, когда каждый php-процесс работает 6 часов, а событие - 12 часов. Я использую php artisan queue:restart в crontab и супервизоре для периодического перезапуска процессов, чтобы в любом случае избежать потребления памяти.

TL; DR: почему добавление gc_collect_cycles () заставляет PHP намного меньше потреблять память?

Сборщик мусора включен по умолчанию

php -i | grep enable_gc                                                
zend.enable_gc => On => On

НЕТ таких звонков, как gc_disable (); ini_set ('zend.enable_gc', ложь);

Также возможно принудительно собрать циклы, даже если возможный корневой буфер еще не заполнен. Для этого вы можете использовать функцию gc_collect_cycles (). Эта функция вернет, сколько циклов было собрано алгоритмом. Обоснование возможности включать и выключать механизм и самостоятельно инициировать сбор цикла заключается в том, что некоторые части вашего приложения могут быть очень чувствительными ко времени.
Jared Farrish 04.08.2018 13:47
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
1
1 175
2

Ответы 2

Насколько я могу судить, --daemon действительно является постоянным запросом, поэтому он не очищает память по умолчанию. Если handle () недолговечен, я бы подумал о queue:listen, так как это завершит запрос после завершения задачи, что автоматически освободит память. Если есть вероятность, что две из этих задач могут совпадать вместе (то есть очень длинные задачи, выполнение которых занимает много времени), то, вероятно, будет достаточно флага gc_collect_cycles () и --daemon.

Однако есть накладные расходы производительности, связанные с ручным сбросом циклов gc. Поэтому слишком частое выполнение этого может привести к снижению производительности - если handle () - недолговечный процесс, возможно, не стоит вводить gc_collect_cycles (). Зависит от архитектуры и того, что происходит в фоновом режиме. Если это недолговечный процесс, который быстро и постоянно вызывается, это может быть сценарий для сохранения постоянного демона и ручного сброса gc вместо начальной загрузки Laravel вверх и вниз. На самом деле просто зависит.

gc_collect_cycles () просто сбрасывает циклы с большей частотой, а не автоматически. Обычно для одиночных запросов он ожидает произвольного количества zval, 10 000, прежде чем он автоматически проверит, что можно выгрузить из корневого буфера. Или он автоматически обрабатывает его в конце запроса. Номер можно изменить через конфигурацию PHP и перекомпиляцию.

PHP 7.3 также внесет некоторые улучшения в сборку мусора (для определенных сценариев, но не в целом), поэтому обязательно обновите PHP, если это возможно.

Источники:

Утечка памяти очереди демона Laravel

http://php.net/manual/en/features.gc.collecting-cycles.php

Я использую следующий код для удаления файла гостевого сеанса, который может помочь:

    $c = 0;
    $files = File::files(storage_path().'/framework/sessions');

    foreach ($files as $f) {
        $file_content = file_get_contents($f);

        $arrFileData = unserialize($file_content);
        $dtCreated = Carbon::createFromTimestamp($arrFileData['_sf2_meta']['u']);
        $dtNow = Carbon::now();
        $diffInHours = $dtNow->diffInHours($dtCreated);
        //if file is older than 2h & not found 'login_web_' then remove file
        if ($diffInHours > 2 && strpos($file_content, 'login_web_') === false) {
            $c++;
            @unlink($f);
        }
    }
    echo "Clear unnecessary sessions: ".$c;

Другие вопросы по теме