Reciclaje de memoria en workers PHP de larga ejecución

Resumen: técnicas prácticas para controlar y reciclar memoria en procesos PHP de larga ejecución (queues, daemons, RoadRunner/Swoole) y mantener la huella de memoria estable.

Introducción

Los workers PHP de larga ejecución (colas, daemons, RoadRunner, Swoole) tienden a crecer en memoria con el tiempo: referencias no liberadas, objetos grandes retenidos y fragmentación del gestor de memoria provocan aumento del RSS y degradación del rendimiento.

Este artículo condensa estrategias prácticas para reciclar memoria sin recurrir a reinicios agresivos por defecto: límites controlados, limpieza explícita y patrones de procesamiento que reducen la presión de memoria.

  • Referencias retenidas en closures y objetos con referencias circulares.
  • Variables estáticas que acumulan cachés ilimitados.
  • Procesamiento en lotes demasiado grandes (arrays/objetos en memoria).
  • Fragmentación interna del gestor de memoria de Zend o fugas en extensiones (ej.: pdo_mysql).

Prerrequisitos

Antes de aplicar estas técnicas asegúrate de tener control sobre la ejecución del worker y acceso a las extensiones/funciones necesarias.

  • PHP CLI con soporte para pcntl si vas a implementar reinicios controlados.
  • Capacidad de supervisión/respawn (supervisor, systemd, o el propio orquestador de RoadRunner/Swoole).
  • Acceso a herramientas de monitorización (ps, pmap, logs de memoria).

Desarrollo

Procedimiento

  1. Establecer límites y reinicios controlados.
  2. Eliminar referencias y forzar recolección de ciclos.
  3. Procesar en chunks para evitar picos de memoria.
  4. Reutilizar objetos pesados (pooling) en vez de recrearlos constantemente.
  5. Monitorizar tendencias y métricas de uso de memoria.

A continuación ejemplos de implementación de cada punto crítico.

1) Reinicio controlado: comprobar uso de memoria y salir para que el supervisor recree el proceso.

<?php
// dentro del loop principal del worker
if (memory_get_usage(true) > 256 * 1024 * 1024) {
    // salir para que el supervisor o manager respawnee un proceso limpio
    exit(1);
}
Lenguaje del código: PHP (php)

2) Limpieza explícita de referencias y recolección de ciclos: unset no siempre basta si existen referencias circulares.

<?php
// después de procesar una tarea pesada
unset($largeStructure);
// forzar recolección de ciclos si hay objetos con referencias circulares
gc_collect_cycles();
Lenguaje del código: PHP (php)

3) Chunking: evitar cargar datasets completos en memoria. Procesa por lotes y libera cada lote.

<?php
foreach (array_chunk($rows, 5000) as $chunk) {
    process($chunk);
    unset($chunk);
    gc_collect_cycles();
}
Lenguaje del código: PHP (php)

4) Reutilización (pooling): evita crear y destruir objetos pesados frecuentemente. Mantén conexiones o parsers en pool cuando sea seguro.

5) Monitorización: usa herramientas del sistema y funciones internas para trazar tendencias de memoria y detectar fugas tempranas.

ps -o pid,rss,cmd -C php
# o para inspección puntual de PID
pmap <PID> | tail -n 1
Lenguaje del código: Bash (bash)

Ejemplos

Ejemplo de loop de worker que combina chequeo de memoria, chunking y recolector de ciclos.

<?php
// worker.php - bucle simplificado
while (true) {
    $rows = fetchPendingRows(50000); // pseudocódigo

    foreach (array_chunk($rows, 5000) as $chunk) {
        process($chunk);
        unset($chunk);
        gc_collect_cycles();
    }

    // chequeo de memoria: salir si supera 256MB para que el supervisor reinicie
    if (memory_get_usage(true) > 256 * 1024 * 1024) {
        exit(1);
    }

    // dormir o esperar por nueva tarea
    usleep(100000);
}
Lenguaje del código: PHP (php)

Checklist

  1. Habilitar y probar reinicios controlados (pcntl o supervisión externa).
  2. Identificar y eliminar referencias circulares; usar gc_collect_cycles tras tareas pesadas.
  3. Procesar en chunks y liberar cada lote explícitamente.
  4. Reutilizar objetos pesados mediante pooling cuando sea seguro.
  5. Registrar y monitorizar memoria (memory_get_peak_usage, ps, pmap) para detectar tendencias.

Trata la memoria como una moneda: mézclala, recíclala y no la derroches en procesos de larga vida.

Conclusión

Workers PHP de larga ejecución son útiles, pero requieren disciplina: límites claros, limpieza explícita y monitorización. Implementa reinicios controlados, limpia referencias, procesa por chunks y registra tendencias para mantener la huella de memoria saneada.

Si no tienes información para afirmar compatibilidades o comportamientos específicos de versiones en tu entorno, prueba primero en un entorno de staging y mide antes de aplicar en producción.

Comments

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *