Sobre las fugas de memoria
Webman es un marco de trabajo de PHP que reside en memoria, por lo que necesitamos prestar un poco de atención a las fugas de memoria. Sin embargo, los desarrolladores no deben preocuparse demasiado, porque las fugas de memoria ocurren en condiciones extremadamente raras y son fáciles de evitar. La experiencia de desarrollo en Webman es prácticamente la misma que en marcos de trabajo tradicionales, sin necesidad de realizar operaciones adicionales para la gestión de memoria.
Consejo
El proceso monitor que viene con Webman supervisará el uso de memoria de todos los procesos. Si el uso de memoria de un proceso se acerca al valor definido pormemory_limit
en php.ini, el proceso correspondiente se reiniciará automáticamente de manera segura, lo que permite liberar memoria, sin afectar la actividad empresarial durante ese tiempo.
Definición de fuga de memoria
A medida que aumentan las solicitudes, la memoria utilizada por Webman también aumenta ilimitadamente (ten en cuenta que es ilimitadamente), alcanzando varios cientos de MB o incluso más; esto se considera una fuga de memoria. Si la memoria crece, pero después se estabiliza, no se considera una fuga de memoria.
Es normal que un proceso consuma decenas de MB de memoria, y cuando un proceso maneja solicitudes extremadamente grandes o mantiene una gran cantidad de conexiones, es común que la memoria ocupada por un único proceso alcance los cientos de MB. Esta parte de la memoria puede no ser completamente devuelta al sistema operativo por PHP, sino que se deja para su reutilización. Por lo tanto, puede ocurrir que después de procesar una solicitud grande, la memoria ocupada aumente y no se libere; esto es un fenómeno normal. (Llamar al método gc_mem_caches()
puede liberar parte de la memoria libre).
Cómo ocurren las fugas de memoria
Las fugas de memoria ocurren solo si se cumplen las siguientes dos condiciones:
- Existe un array de largo ciclo de vida (ten en cuenta que es un array de largo ciclo de vida, un array normal no es un problema).
- Y este array de largo ciclo de vida se expande ilimitadamente (la aplicación sigue insertando datos en él sin limpiarlos).
Si las condiciones 1 y 2 se cumplen simultáneamente (ten en cuenta que se deben cumplir simultáneamente), se producirá una fuga de memoria. Si no se cumplen las condiciones anteriormente mencionadas o solo se cumple una de ellas, entonces no se considera fuga de memoria.
Arrays de largo ciclo de vida
Los arrays de largo ciclo de vida en Webman incluyen:
- Arrays con la palabra clave static.
- Propiedades de array en un singleton.
- Arrays con la palabra clave global.
Nota
Se permite el uso de datos de largo ciclo de vida en Webman, pero es necesario asegurarse de que los datos dentro de estos arrays sean limitados y que el número de elementos no se expanda infinitamente.
A continuación se presentan ejemplos.
Array static en expansión infinita
class Foo
{
public static $data = [];
public function index(Request $request)
{
self::$data[] = time();
return response('hello');
}
}
El array $data
definido con la palabra clave static
es un array de largo ciclo de vida, y en el ejemplo, el array $data
se expande constantemente a medida que aumentan las solicitudes, lo que provoca una fuga de memoria.
Propiedad de array de singleton en expansión infinita
class Cache
{
protected static $instance;
public $data = [];
public function instance()
{
if (!self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
public function set($key, $value)
{
$this->data[$key] = $value;
}
}
Código de llamada
class Foo
{
public function index(Request $request)
{
Cache::instance()->set(time(), time());
return response('hello');
}
}
Cache::instance()
devuelve una instancia singleton de Cache, que es una instancia de clase de largo ciclo de vida. Aunque la propiedad $data
no utiliza la palabra clave static
, dado que la clase en sí misma es de largo ciclo de vida, el array $data
también es de largo ciclo de vida. A medida que se agregan diferentes claves al array $data
, la memoria ocupada por el programa también aumenta, causando así una fuga de memoria.
Nota
Si las claves agregadas conCache::instance()->set(key, value)
tienen un número limitado, no habrá fuga de memoria, ya que el array$data
no se expande infinitamente.
Array global en expansión infinita
class Index
{
public function index(Request $request)
{
global $data;
$data[] = time();
return response($foo->sayHello());
}
}
El array definido con la palabra clave global no será reciclado al concluir la ejecución de la función o el método de la clase, por lo que es un array de largo ciclo de vida. El código anterior generará fugas de memoria a medida que aumentan las solicitudes. Asimismo, un array definido con la palabra clave static dentro de una función o método también es un array de largo ciclo de vida, si el array se expande infinitamente, también causará una fuga de memoria, como en el siguiente ejemplo:
class Index
{
public function index(Request $request)
{
static $data = [];
$data[] = time();
return response($foo->sayHello());
}
}
Recomendaciones
Se recomienda a los desarrolladores que no se preocupen demasiado por las fugas de memoria, ya que son muy raras. Si, por desgracia, ocurren, podemos identificarlas mediante pruebas de carga para localizar el código que las causa. Incluso si los desarrolladores no encuentran el punto de fuga, el servicio monitor que viene con Webman reiniciará de manera segura los procesos que experimentan fugas de memoria, liberando así la memoria.
Si realmente deseas evitar las fugas de memoria en la medida de lo posible, puedes considerar las siguientes sugerencias:
- Trata de evitar el uso de arrays con las palabras clave
global
ystatic
. Si los usas, asegúrate de que no se expandan infinitamente. - Para las clases que no conoces bien, es mejor no usar singletons; utiliza la palabra clave new para inicializarlas. Si necesitas un singleton, revisa si tiene propiedades de array en expansión infinita.