Riguardo alle perdite di memoria
webman è un framework in memoria persistente, quindi dobbiamo prestare attenzione al problema delle perdite di memoria. Tuttavia, gli sviluppatori non devono preoccuparsi troppo, poiché le perdite di memoria si verificano solo in condizioni molto estreme e sono facilmente evitabili. L'esperienza di sviluppo con webman è fondamentalmente simile a quella dello sviluppo con framework tradizionali, e non è necessario eseguire operazioni superflue per la gestione della memoria.
Suggerimento
Il processo monitor fornito da webman monitora l'utilizzo della memoria di tutti i processi. Se l'utilizzo della memoria di un processo si avvicina al valore impostato damemory_limit
in php.ini, il processo verrà automaticamente riavviato in modo sicuro, liberando la memoria senza alcun impatto sulle attività aziendali.
Definizione di perdita di memoria
Con l'aumento continuo delle richieste, la memoria occupata da webman aumenta infinito (nota: infinito), raggiungendo centinaia di MB o anche di più; questo è una perdita di memoria. Se la memoria cresce ma poi smette di crescere, non si considera una perdita di memoria.
È normale che un processo utilizzi decine di MB di memoria. Quando un processo gestisce richieste molto grandi o mantiene un gran numero di connessioni, l'occupazione di memoria di un singolo processo può anche superare i cento MB. Questa memoria utilizzata potrebbe non essere completamente restituita al sistema operativo da php. Viene invece mantenuta per il riutilizzo, quindi potrebbe verificarsi un aumento dell'occupazione della memoria dopo la gestione di una grande richiesta, senza rilasciare la memoria; questo è un fenomeno normale. (L'invocazione del metodo gc_mem_caches()
può liberare parte della memoria non utilizzata.)
Come avviene la perdita di memoria
Una perdita di memoria si verifica solo se sono soddisfatti i seguenti due requisiti:
- Esiste un array a lungo ciclo di vita (nota: è un array a lungo ciclo di vita, non un normale array)
- E questo array a lungo ciclo di vita si espande all'infinito (i dati vengono continuamente inseriti nell'array senza mai pulirli)
Se entrambi i requisiti 1 e 2 sono soddisfatti contemporaneamente (nota: devono essere soddisfatti contemporaneamente), allora si verificherà una perdita di memoria. Se non si soddisfano i requisiti sopra o se si soddisfa solo uno di essi, non si tratta di una perdita di memoria.
Arrays a lungo ciclo di vita
In webman, gli arrays a lungo ciclo di vita comprendono:
- Arrays definiti con la parola chiave
static
- Proprietà degli array in un singleton
- Arrays definiti con la parola chiave
global
Nota
In webman è consentito utilizzare dati a lungo ciclo di vita, ma è necessario garantire che i dati contenuti in questi dati siano limitati e che il numero di elementi non si espanda all'infinito.
Di seguito vengono forniti esempi per illustrare.
Array statico in espansione infinita
class Foo
{
public static $data = [];
public function index(Request $request)
{
self::$data[] = time();
return response('hello');
}
}
L'array $data
definito con la parola chiave static
è un array a lungo ciclo di vita e, nell'esempio, l'array $data
si espande continuamente man mano che le richieste aumentano, causando una perdita di memoria.
Proprietà di array singleton in espansione 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;
}
}
Codice di chiamata
class Foo
{
public function index(Request $request)
{
Cache::instance()->set(time(), time());
return response('hello');
}
}
Cache::instance()
restituisce un singleton Cache, che è un'istanza di classe a lungo ciclo di vita. Anche se la proprietà $data
non utilizza la parola chiave static
, poiché la classe stessa è a lungo ciclo di vita, anche $data
è un array a lungo ciclo di vita. Man mano che vengono aggiunti dati a $data
con chiavi diverse, l'occupazione di memoria del programma aumenta, causando una perdita di memoria.
Nota
Se le chiavi aggiunte tramiteCache::instance()->set(key, value)
sono di quantità limitata, non si verificherà una perdita di memoria, poiché l'array$data
non si espande all'infinito.
Array global in espansione infinita
class Index
{
public function index(Request $request)
{
global $data;
$data[] = time();
return response($foo->sayHello());
}
}
L'array definito con la parola chiave global non verrà deallocato dopo che una funzione o un metodo della classe è stato eseguito, quindi è un array a lungo ciclo di vita. Il codice sopra, con l'aumento delle richieste, causerà una perdita di memoria. Analogamente, un array definito con la parola chiave static
all'interno di una funzione o di un metodo è anch'esso un array a lungo ciclo di vita e, se l'array si espande all'infinito, causerà una perdita di memoria, ad esempio:
class Index
{
public function index(Request $request)
{
static $data = [];
$data[] = time();
return response($foo->sayHello());
}
}
Raccomandazioni
Si consiglia agli sviluppatori di non prestare particolare attenzione alle perdite di memoria, poiché esse si verificano raramente. Se si verifica una perdita di memoria, possiamo identificare il codice responsabile attraverso test di stress, per poi localizzare il problema. Anche se gli sviluppatori non riescono a trovare il punto di perdita, il servizio monitor di webman riavvierà in modo sicuro il processo che ha subito la perdita di memoria, liberando la memoria.
Se desideri davvero cercare di evitare le perdite di memoria, puoi seguire i seguenti suggerimenti.
- Cerca di non utilizzare arrays definiti con le parole chiave
global
ostatic
, e se li utilizzi, assicurati che non possano espandersi all'infinito. - Per classi non familiari, cerca di non utilizzare singleton, ma inizializza con la parola chiave new. Se è necessario un singleton, controlla se ci sono proprietà di array in espansione infinita.