Über Speicherlecks
Webman ist ein im Speicher verankertes Framework, daher sollten wir ein wenig auf die Möglichkeit von Speicherlecks achten. Entwickler brauchen sich jedoch nicht übermäßig Sorgen zu machen, da Speicherlecks unter extremen Bedingungen auftreten und leicht vermieden werden können. Die Entwicklung mit Webman ähnelt der Erfahrung mit traditionellen Frameworks, sodass keine zusätzlichen Maßnahmen zur Speicherverwaltung getroffen werden müssen.
Hinweis
Der mitgelieferte Monitor-Prozess von Webman überwacht die Speichernutzung aller Prozesse. Wenn der Speicher eines Prozesses kurz davor steht, den in php.ini festgelegten Wertmemory_limit
zu erreichen, wird der betreffende Prozess automatisch sicher neu gestartet, um den Speicher freizugeben, ohne dass dies Auswirkungen auf den Geschäftsbetrieb hat.
Definition von Speicherlecks
Mit zunehmender Anzahl an Anfragen steigt der von Webman verwendete Speicher unbegrenzt (bitte beachten Sie, dass es unbegrenzt ist), bis hin zu mehreren hundert MB oder mehr, was ein Speicherleck darstellt. Wenn der Speicher zwar wächst, aber daraufhin nicht weiter wächst, zählt dies nicht als Speicherleck.
Ein normaler Speicherverbrauch von mehreren Dutzend MB pro Prozess ist ganz normal. Wenn ein Prozess große Anfragen bearbeitet oder eine große Anzahl von Verbindungen verwaltet, kann der Speicherverbrauch eines einzelnen Prozesses leicht über 100 MB steigen. In solchen Fällen gibt PHP möglicherweise nicht den gesamten Speicher an das Betriebssystem zurück, sondern hält ihn für die Wiederverwendung zurück, was dazu führen kann, dass der Speicherverbrauch nach der Bearbeitung einer großen Anfrage ansteigt und nicht freigegeben wird. Dies ist ein normales Verhalten. (Der Aufruf der Methode gc_mem_caches()
kann einen Teil des freien Speichers freigeben.)
Wie Speicherlecks entstehen
Ein Speicherleck tritt nur dann auf, wenn folgende zwei Bedingungen erfüllt sind:
- Es gibt ein langlebiges Array (beachten Sie, es ist ein langlebiges Array, normale Arrays sind unproblematisch).
- Und dieses langlebige Array dehnt sich unbegrenzt aus (das Geschäftsmodell fügt unendlich viele Daten hinzu, ohne diese zu bereinigen).
Wenn die Bedingungen 1 und 2 gleichzeitig erfüllt sind (Achtung: gleichzeitig erfüllt), entsteht ein Speicherleck. Andernfalls, wenn eine oder keine der Bedingungen erfüllt ist, handelt es sich nicht um ein Speicherleck.
Langlebige Arrays
In Webman gibt es langlebige Arrays wie folgt:
- Arrays mit dem Schlüsselwort
static
- Einzelinstanz-Array-Attribute
- Arrays mit dem Schlüsselwort
global
Achtung
In Webman ist die Verwendung langlebiger Daten zulässig, es muss jedoch sichergestellt werden, dass die Daten innerhalb dieser Arrays endlich sind und die Anzahl der Elemente sich nicht unbegrenzt ausdehnt.
Im Folgenden werden entsprechende Beispiele gegeben.
Unbegrenzt wachsende static
-Arrays
class Foo
{
public static $data = [];
public function index(Request $request)
{
self::$data[] = time();
return response('hello');
}
}
Das mit dem Schlüsselwort static
definierte Array $data
ist ein langlebiges Array, und im Beispiel wächst das Array $data
mit jeder Anfrage kontinuierlich, was zu einem Speicherleck führt.
Unbegrenzt wachsende Einzelinstanz-Array-Attribute
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;
}
}
Aufrufcode
class Foo
{
public function index(Request $request)
{
Cache::instance()->set(time(), time());
return response('hello');
}
}
Cache::instance()
gibt eine Cache-Einzelinstanz zurück, die eine langlebige Klasseninstanz ist. Obwohl das Attribut $data
nicht das Schlüsselwort static
verwendet, ist es aufgrund der langlebigen Klasse ebenfalls ein langlebiges Array. Wenn kontinuierlich verschiedene Schlüssel in das $data
-Array hinzugefügt werden, wächst der Speicherverbrauch des Programms stetig und verursacht ein Speicherleck.
Achtung
Wenn die durchCache::instance()->set(key, value)
hinzugefügten Schlüssel eine begrenzte Anzahl haben, wird kein Speicherleck auftreten, da sich das$data
-Array nicht unbegrenzt ausdehnt.
Unbegrenzt wachsende global
-Arrays
class Index
{
public function index(Request $request)
{
global $data;
$data[] = time();
return response($foo->sayHello());
}
}
Das mit dem Schlüsselwort global
definierte Array wird nach der Ausführung der Funktion oder Method nicht freigegeben, es handelt sich daher um ein langlebiges Array. Der obige Code verursacht mit zunehmenden Anfragen ein Speicherleck. Gleiches gilt für in Funktionen oder Methoden mit dem Schlüsselwort static
definierte Arrays, die ebenfalls langlebig sind. Wenn diese Arrays unbegrenzt wachsen, kommt es ebenfalls zu Speicherlecks, wie im folgenden Beispiel:
class Index
{
public function index(Request $request)
{
static $data = [];
$data[] = time();
return response($foo->sayHello());
}
}
Empfehlungen
Es wird empfohlen, dass Entwickler sich nicht besonders um Speicherlecks kümmern, da sie sehr selten auftreten. Falls sie leider doch auftreten, können wir durch Lasttests herausfinden, welcher Teil des Codes das Leck verursacht und damit das Problem lokalisieren. Selbst wenn Entwickler den Ursprung des Lecks nicht finden, wird der von Webman mitgelieferte Monitor-Dienst gegebenenfalls sicher die Prozesse, in denen Speicherlecks auftreten, neu starten und den Speicher freigeben.
Wenn Sie wirklich versuchen möchten, Speicherlecks zu vermeiden, beachten Sie bitte die folgenden Empfehlungen:
- Verwenden Sie nach Möglichkeit keine Arrays mit den Schlüsselwörtern
global
oderstatic
. Wenn Sie sie verwenden, stellen Sie sicher, dass sie sich nicht unbegrenzt ausdehnen. - Verwenden Sie bei unbekannten Klassen nach Möglichkeit keine Einzelinstanzen, sondern initialisieren Sie sie mit dem Schlüsselwort
new
. Wenn eine Einzelinstanz erforderlich ist, überprüfen Sie, ob sie unbegrenzt wachsende Array-Attribute hat.