jueves, 22 de octubre de 2015

Evitando el consumo excesivo de memoria con Doctrine y Symfony2

Doctrine es el ORM que utiliza el framework Symfony2. Es un producto muy completo, con muchas opciones, pero tiene un pequeño problema cuando se manejan grandes cantidades de información.


El problema

He tenido un problema con un script que mantiene sincronizadas dos bases de datos (una MySQL y otra PostgreSQL, en servidores remotos, aunque no venga al caso). Se trata de un comando de consola de Symfony2 que se ejecuta periódicamente a través de un cron. Llevaba meses funcionando bien hasta que de repente:

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

Vi el problema enseguida: La cantidad de datos a sincronizar ha crecido últimamente; Así que rediseñé el algoritmo para que funcionase con bloques de 500 registros en lugar de tratar de golpe todos los registros.

Pero eso no solucionó el problema.


La solución

Podría haber puesto el sufrido ini_set("memory_limit", -1) pero eso sólo haría que el proceso gastase más y más memoria del sistema. El recolector de basura de PHP no libera los objetos mientras haya referencias apuntando a los mismos y Doctrine internamente mantiene esas referencias a no ser que se liberen manualmente.

Para ello el EntityManager de Doctrine en Symfony2 cuenta con un par de funciones: detach y clear. Veamos un ejemplo:

$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('...')->findBy(array('...'));
foreach ($entities as $entity) {
    $entity->doSomething();
    // (....)
    $em->detach($entity);
    unset($entity);
}
$em->clear();

La instrucción detach desvincula una entidad del EntityManager; es decir elimina cualquier referencia a la entidad. Los cambios realizados en la entidad, incluyendo su borrado, no se sincronizarán con la base de datos posteriormente a la desvinculación. Por su parte clear desvincula de golpe todas las entidades cargadas en el EntityManager.


Referencias

No hay comentarios:

Publicar un comentario