Heim > Artikel > Backend-Entwicklung > Zend-Speichermanager für PHP
Zend Memory Manager, oft abgekürzt als ZendMM oder ZMM, ist eine C-Schicht Entwickelt, um die Möglichkeit zu bieten, dynamischen anforderungsgebundenen Speicher zuzuweisen und freizugeben.
Achten Sie auf „Anfragebindung“ im obigen Satz.
ZendMM ist mehr als nur eine klassische Ebene auf der dynamischen Speicherzuweisung von libc, die hauptsächlich durch zwei API-Aufrufe repräsentiert wird malloc()/free()
. Bei ZendMM geht es um den anfragegebundenen Speicher, den PHP bei der Verarbeitung einer Anfrage zuweisen muss.
Verwandte Lernempfehlungen: PHP-Programmierung vom Einstieg bis zur Beherrschung
PHP Es ist eine Shared-Nothing-Architektur. Nun ja, nicht zu 100 %. Weitere Informationen zu Schritten und Zyklen.
ZendMM verfügt über eine API, die den dynamischen Allokator von libc durch Kopieren seiner API ersetzt. Programmierer müssen bei der Bearbeitung von Anforderungen diese API anstelle des Allokators von libc verwenden. Wenn PHP beispielsweise eine Anfrage verarbeitet, analysiert es die PHP-Datei. Diese führen beispielsweise zu Deklarationen von Funktionen und Klassen. Wenn der Compiler mit dem Kompilieren einer PHP-Datei beginnt, weist er dynamischen Speicher zum Speichern der erkannten Klassen und Funktionen zu. PHP gibt diese jedoch am Ende der Anfrage frei. Standardmäßig vergisst PHPPHP kann Hunderte oder Tausende von Anfragen im selben Prozess bearbeiten. Standardmäßig vergisst PHP alle Informationen über die aktuelle Anfrage, nachdem diese abgeschlossen ist.
Die „Vergessen“-Nachricht wird so interpretiert, dass alle dynamischen Puffer freigegeben werden, die während der Verarbeitung der Anfrage zugewiesen wurden. Dies bedeutet, dass Sie beim Verarbeiten einer Anforderung keine herkömmlichen libc-Aufrufe verwenden können, um dynamischen Speicher zuzuweisen. Das ist vollkommen richtig, aber Sie geben sich die Chance, zu vergessen, den Puffer freizugeben.
viele
Informationen von einer Anfrage zur anderen. Es gibt jedoch einige sehr seltene Informationen, die Sie über mehrere Anfragen hinweg beibehalten müssen. Aber das ist nicht üblich.Was kann durch Anfragen unverändert beibehalten werden? Was wir ein persistentes
Objekt nennen. Nochmals: Das ist keine alltägliche Situation. Beispielsweise ändert sich der aktuelle PHP-Ausführungspfad zwischen Anfragen nicht. Seine Informationen werden dauerhaft zugewiesen, was bedeutet, dass herkömmliche libcs aufgerufen werden, um sie zuzuweisen.
Was noch? etwas Schnur. Beispielsweise wird die Zeichenfolge "_SERVER" zwischen Anfragen wiederverwendet, da für jede Anfrage ein malloc ()
PHP-Array erstellt wird. Daher kann die Zeichenfolge
selbst dauerhaft zugewiesen werden, da sie nur einmal zugewiesen wird. Sie müssen Folgendes beachten:$_SERVER
Permanente dynamische Zuordnung.
Sollte nur mit der dynamischen Speicherzuweisungs-API von ZendMM durchgeführt werden.
Wird von ZendMM nicht verfolgt und Sie werden nicht über Lecks benachrichtigt.
zend_string *foo = zend_string_init("foo", strlen("foo"), 0);Dies ist eine dauerhafte Zuweisung:
zend_string *foo = zend_string_init("foo", strlen("foo"), 1);Die gleiche HashTable.
Anforderungsgebundene Zuweisung:
zend_array ar; zend_hash_init(&ar, 8, NULL, NULL, 0);
Persistente Zuweisung:
zend_array ar; zend_hash_init(&ar, 8, NULL, NULL, 1);
Es ist bei allen verschiedenen Zend-APIs immer das Gleiche. Normalerweise als letzter Parameter übergeben, bedeutet
„0“
„1“
bedeutet „Ich möchte ZendMM verwenden.“ um diese Struktur zuzuweisen, also wird die Bindung angefordert“ oder„1“ bedeutet „Ich möchte ZendMM verwenden, um diese Struktur zuzuweisen, also wird die Bindung angefordert“ Rufen Sie traditionelle libcs auf, um diese Struktur zuzuweisen ". Anscheinend stellen diese Strukturen eine API bereit, die sich merkt, wie sie die Struktur zugewiesen hat, sodass bei ihrer Zerstörung die richtige Freigabefunktion verwendet wird. Also in Code wie diesem: malloc()
zend_string_release(foo); zend_hash_destroy(&ar);API weiß, ob diese Strukturen mithilfe der Anforderungsbindung zugewiesen oder dauerhaft zugewiesen werden. Im ersten Fall wird
verwendet, um sie freizugeben, im zweiten Fall libcs
.Die API befindet sich in Zend/zend_alloc.h
Die API besteht hauptsächlich aus C-Makros, nicht aus Funktionen, wenn Sie sie also debuggen und ihre Funktionsweise verstehen möchten Prinzip: Bitte seien Sie vorbereitet. Diese APIs kopieren die Funktionen von libc, oft mit einem „e“ an den Funktionsnamen. Sie sollten daher nicht den Fehler machen, es gibt nicht viele Details über die API.
Grundsätzlich werden Sie am häufigsten emalloc(size_t)
und efree(void *)
verwenden.
bietet auch ecalloc(size_t nmemb,size_t size)
, das ein einzelnes size
der Größe nmemb
zuweist und die Region auf Null setzt. Wenn Sie ein erfahrener C-Programmierer sind, sollten Sie wissen, dass es nach Möglichkeit besser ist, emalloc()
anstelle von ecalloc()
zu verwenden, da ecalloc()
den Speicherbereich auf Null setzt, was für die Erkennung von Zeigerfehlern wichtig ist und möglicherweise von großem Nutzen ist helfen. Beachten Sie, dass emalloc()
grundsätzlich genauso funktioniert wie libc malloc()
: Es sucht in verschiedenen Pools nach einem ausreichend großen Bereich und stellt Ihnen den am besten geeigneten Platz zur Verfügung. Daher kann es sein, dass Sie einen durch Garbage Collection gesammelten Zeiger erhalten.
und dann safe_emalloc(size_t nmemb,size_t size,size_t offset)
, was emalloc(size * nmemb + offset)
ist, aber es prüft für Sie, ob ein Überlauf vorliegt. Dieser API-Aufruf sollte verwendet werden, wenn die anzugebende Nummer von einer nicht vertrauenswürdigen Quelle (z. B. Userland) stammt.
In Bezug auf Zeichenfolgen ermöglichen estrdup(char *)
und estrndup(char *, size_t len)
das Kopieren von Zeichenfolgen oder binären Zeichenfolgen.
Egal was passiert, der von ZendMM zurückgegebene Zeiger muss durch den Aufruf von ZendMMs efree()
freigegeben werden, und ist nicht free() von libc.
Hinweis
zur dauerhaften Zuordnung. Dauerhafte Zuweisungen bleiben zwischen Anfragen gültig. Normalerweise verwenden Sie dazu die übliche libc
malloc/ free
, aber ZendMM hat einige Abkürzungen für den libc-Allokator: die „persistente“ API. Die API beginnt mit „p“ -Buchstaben und lässt Sie zwischen ZendMM-Zuweisung und dauerhafter Zuweisung wählen. Daher istpemalloc(size_t, 1)
nurmalloc()
,pefree(void *, 1)
istfree()
undpestrdup(void *, 1)
iststrdup()
. Ich sage es nur.
ZendMM bietet die folgenden Funktionen:
ZendMM ist ein PHP-Benutzerland, das dem „ „memory_limit“-Funktion. Jedes einzelne Byte, das mithilfe der ZendMM-Schicht zugewiesen wird, wird gezählt und summiert. Sie wissen, was passiert, wenn das memory_limit der INI erreicht ist. Dies bedeutet auch, dass alle über ZendMM durchgeführten Zuweisungen in memory_get_usage()
im PHP-Benutzerland widergespiegelt werden.
Als Erweiterungsentwickler ist das eine gute Sache, denn so behalten Sie den Überblick über die Heap-Größe Ihres PHP-Prozesses.
Wenn ein Speicherlimitfehler ausgelöst wird, wird die Engine von der aktuellen Codeposition in den Capture-Block freigegeben und dann ordnungsgemäß beendet. Es ist jedoch nicht möglich, zu einem Codespeicherort zurückzukehren, der das Limit überschreitet. Darauf muss man vorbereitet sein.
Theoretisch bedeutet dies, dass ZendMM Ihnen keinen NULL-Zeiger zurückgeben kann. Wenn die Zuweisung durch das Betriebssystem fehlschlägt oder die Zuweisung einen Speicherlimitfehler erzeugt, stößt der Code auf einen Catch-Block und kehrt nicht zu Ihrem Zuweisungsaufruf zurück.
Wenn Sie diesen Schutz aus irgendeinem Grund umgehen müssen, müssen Sie herkömmliche libc-Aufrufe wie malloc()
verwenden. Seien Sie auf jeden Fall vorsichtig und wissen Sie, was Sie tun. Wenn Sie ZendMM verwenden, müssen Sie möglicherweise viel Speicher zuweisen und überschreiten möglicherweise PHPs memory_limit. Verwenden Sie also einen anderen Allokator (wie libc), aber seien Sie vorsichtig: Ihre Erweiterung erhöht die aktuelle Größe des Prozess-Heapspeichers. memory_get_usage()
kann in PHP nicht gesehen werden, aber der aktuelle Heap kann mithilfe von Betriebssystemfunktionen analysiert werden (z. B. /proc/{pid}/maps)
Hinweis
Wenn Sie ZendMM vollständig deaktivieren müssen, können Sie PHP mit der Umgebungsvariablen
USE_ZEND_ALLOC = 0
starten. Auf diese Weise wird jeder Aufruf der ZendMM-API (z. B. emalloc()) an den libc-Aufruf weitergeleitet und ZendMM wird deaktiviert. Dies ist besonders nützlich beim Debuggen des Speichers.
Bedenken Sie die Hauptregel von ZendMM: Es startet, wenn die Anfrage startet, und erwartet dann, dass Sie seine API aufrufen, wenn Sie dynamischen Speicher benötigen, um die Anfrage zu bearbeiten. Wenn die aktuelle Anfrage endet, wird ZendMM heruntergefahren.
Durch das Schließen werden alle Live-Zeiger durchsucht und bei Verwendung des PHP-Debug-Builds werden Sie vor Speicherlecks gewarnt.
Lass es uns etwas klarer erklären: Wenn ZendMM am Ende der aktuellen Anfrage einige aktive Speicherblöcke findet, bedeutet das, dass diese Speicherblöcke lecken. Am Ende der Anfrage sollten keine aktiven Speicherblöcke auf dem ZendMM-Heap vorhanden sein, da derjenige, der Speicher zugewiesen hat, ihn hätte freigeben müssen.
如果您忘记释放块,它们将全部显示在 stderr上。此内存泄漏报告进程仅在以下情况下有效:
这是一个简单泄漏到扩展中的示例:
PHP_RINIT_FUNCTION(example) { void *foo = emalloc(128); }
在启动该扩展的情况下启动 PHP,在调试版本上会在 stderr 上生成:
[Fri Jun 9 16:04:59 2017] Script: '/tmp/foobar.php' /path/to/extension/file.c(123) : Freeing 0x00007fffeee65000 (128 bytes), script=/tmp/foobar.php === Total 1 memory leaks detected ===
当 Zend 内存管理器关闭时,在每个已处理请求的末尾,将生成这些行。
但是要当心:
你必须记住的是 ZendMM 泄漏跟踪是一个不错的奖励工具,但它不能代替真正的 C 内存调试器。
这是使用 ZendMM 时最常见的错误,以及你应该怎么做。
获取有关 PHP 生命周期的信息,以了解在扩展中何时处理请求,何时不处理。如果在请求范围之外使用 ZendMM(例如在MINIT()中),在处理第一个请求之前,ZendMM 会静默清除分配,并且可能会使用after-after-free:根本没有。
使用内存调试器。如果你在 ZendMM 返回的内存区域以下或过去写入内容,则将覆盖关键的 ZendMM 结构并触发崩溃。如果 ZendMM 能够为你检测到混乱,则可能会显示“zend_mm_heap损坏”的消息。堆栈追踪将显示从某些代码到某些 ZendMM 代码的崩溃。ZendMM 代码不会自行崩溃。如果你在 ZendMM 代码中间崩溃,那很可能意味着你在某个地方弄乱了指针。插入你喜欢的内存调试器,查找有罪的部分并进行修复。
如果分配一个 ZendMM 指针(即emalloc()
)并使用 libc 释放它(free()
),或相反的情况:你将崩溃。要严谨对待。另外,如果你将其不知道的任何指针传递给 ZendMM 的efree()
:将会崩溃。
Das obige ist der detaillierte Inhalt vonZend-Speichermanager für PHP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!