Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Erklärung des PHP7-Garbage-Collection-Mechanismus

Detaillierte Erklärung des PHP7-Garbage-Collection-Mechanismus

藏色散人
藏色散人nach vorne
2019-07-12 13:57:177859Durchsuche

Detaillierte Erklärung des PHP7-Garbage-Collection-Mechanismus

Detaillierte Erklärung des PHP7-Garbage-Collection-Mechanismus

Der Autor interessierte sich vor ein paar Tagen für dieses Thema, also Ich habe online gesucht, fast alle davon sind der Garbage-Collection-Mechanismus von PHP 5. Obwohl die im GC-Teil von PHP5 zu PHP7 vorgenommenen Änderungen relativ gering sind, denke ich, dass es dennoch notwendig ist, einen separaten Blog-Beitrag zu verfassen. Sofern nicht anders angegeben, ist die PHP-Version 7.2

Der von Variablen in PHP belegte Speicherplatz muss nicht manuell zurückgewonnen werden. Der Kernel übernimmt diesen Teil der Arbeit für uns. Im Vergleich zu C erleichtert dies unsere Bedienung erheblich.

Dieser Artikel erklärt hauptsächlich den GC-Mechanismus von Variablen

Um unseren PHP-GC zu verstehen, halte ich es für notwendig, die zugrunde liegende Implementierung unserer PHP-Variablen vorzustellen.

Die Struktur von zval

// php 变量对于的c结构体
struct _zval_struct {
    zend_value value;
    union {
       ……
    } u1;
    union {
        ……
    } u2;
};

Da es hauptsächlich um die Speicherbereinigung geht, finden Sie hier eine kurze Einführung in die Funktionen von u1 u2 Union

Die Die Struktur von u1 ist komplizierter. Ich denke, sie wird hauptsächlich zur Identifizierung von Variablentypen

u2 verwendet. Die meisten davon sind Hilfsfelder, die Implementierung interner Funktionen von Variablen, die Verbesserung der Cache-Freundlichkeit usw.

Als nächstes kommt unser Protagonist

zend_value Es ist auch eine in die Struktur eingebettete Union

typedef union _zend_value {
    zend_long         lval;//整形
    double            dval;//浮点型
    zend_refcounted  *counted;//获取不同类型的gc头部
    zend_string      *str;//string字符串
    zend_array       *arr;//数组
    zend_object      *obj;//对象
    zend_resource    *res;//资源
    zend_reference   *ref;//是否是引用类型
  
    // 忽略下面的结构,与我们讨论无关
    zend_ast_ref     *ast;
    zval             *zv;
    void             *ptr;
    zend_class_entry *ce;
    zend_function    *func;
    struct {
        ZEND_ENDIAN_LOHI(
            uint32_t w1,
            uint32_t w2)
    } ww;
} zend_value;

Die Art der Referenzzählung zend_refcounted *counted wird im Wert von zval aufgezeichnet darauf basierend.

typedef struct _zend_refcounted_h {
    uint32_t         refcount;          /* reference counter 32-bit */
    union {
        struct {
            ZEND_ENDIAN_LOHI_3(
                zend_uchar    type,
                zend_uchar    flags,    /* used for strings & objects */
                uint16_t      gc_info)  /* keeps GC root number (or 0) and color */
        } v;
        uint32_t type_info;
    } u;
} zend_refcounted_h;

Alle komplexen Typdefinitionen beginnen mit der Struktur zend_refcounted_h. Zusätzlich zur Referenzzählung verfügt diese Struktur auch über GC-bezogene Strukturen. Daher muss sich der GC beim GC-Recycling nicht um die Details kümmern. Was ist der Typ? Alle können als zend_refcounted*-Strukturen behandelt werden.

Automatisches Recycling von Variablen

Zusätzlich zu Array- und Objekttypvariablen in PHP rest Die meisten von ihnen werden automatisch recycelt

php Das Recycling gewöhnlicher Variablen hängt von der Anzahl der Verweise auf die Variable ab.

Offizielles Beispiel

$a = 1;
$b = $a;
xdebug_debug_zval('a');
$a =10;
xdebug_debug_zval('a');
unset($a);
xdebug_debug_zval('a');

Ergebnis

a:
(refcount=2, is_ref=0),int 1
a:
(refcount=1, is_ref=0),int 10
a: no such symbol

Sie können sehen, dass bei $a =10 der COW-Mechanismus (Copy-on-Write) von PHP beteiligt ist, $b Eine Kopie des ursprünglichen $a wird kopiert und die Referenzbeziehung zwischen ihnen wird freigegeben, sodass die Anzahl der Referenzen (Refcount) von a auf 1 reduziert wird.

Dann wird die Anzahl der Verweise auf a 0, nachdem wir t($a) verwendet haben. Dies wird als Müllvariable betrachtet und gibt Speicherplatz frei.

Geben Sie ein Beispiel

$a = [1];
$a[1] = &$a;
unset($a);

Vor unset($a) ist der Typ von $a ein Referenztyp

a:
(refcount=2, is_ref=1),
array (size=2)
  0 => (refcount=1, is_ref=0),int 1
  1 => (refcount=2, is_ref=1),
    &array<

Detaillierte Erklärung des PHP7-Garbage-Collection-Mechanismus

unset( $ a) Danach sieht es so aus:

Detaillierte Erklärung des PHP7-Garbage-Collection-Mechanismus

Zu diesem Zeitpunkt, wenn wir die Operation deaktivieren, ändert sich der Refcount von 2 auf 1, da es einen internen Referenzzeiger gibt zu $a, also wo es extern ist Der belegte Raum wird nicht zerstört.

Dann ist unser externer Bezug kaputt und wir können ihn nicht nutzen. Es wird zu einem „Waise“, was in der C-Sprache als Wild-Zeiger bezeichnet wird. In PHP nennt man das einen Zirkelverweis. Speicherleck. Wenn Sie die Variable zerstören möchten, können Sie nur warten, bis das PHP-Skript beendet ist.

Speicherlecks durch Zirkelverweise

Um diesen Müll zu beseitigen, werden zwei Kriterien eingeführt

● Wenn die Referenzanzahl auf reduziert wird Null, die Variable, in der es sich befindet. Der Container wird gelöscht (frei) und ist kein Müll

● Wenn der Referenzzähler eines zval nach der Reduzierung immer noch größer als 0 ist, wird er in den Müll verschoben Zyklus. Zweitens können Sie während eines Garbage-Zyklus herausfinden, welche Teile Garbage sind, indem Sie prüfen, ob die Referenzanzahl um 1 reduziert wird und welche Variablencontainer keine Referenzen haben.

Zirkuläre Referenzen treten grundsätzlich nur in Arrays und Objekten auf, weil es selbst eine Referenz ist

Der Recyclingprozess von Objekt und Array

Die Garbage Collection von PHP7 besteht aus zwei Teilen: einem ist der Garbage Collector und der andere ist der Garbage Collection-Algorithmus.

Der Garbage Collector sammelt die gerade erwähnten Elemente, die möglicherweise Müll sind, im Recyclingpool, dh die zend_refcount-Informationen der Variablen werden im Recyclingpool abgelegt. Wenn der Wert des Recyclingpools einen bestimmten Wert erreicht, wird dieser einheitlich verarbeitet.

Der Verarbeitungsprozess ist relativ einfach.

Durchlaufen Sie jede Variable im Recycling-Pool und dann jedes Mitglied basierend auf jeder Variablen. Wenn die Mitglieder noch verschachtelt sind, fahren Sie mit dem Durchlaufen fort. Setzen Sie dann den simulierten Refcount aller Mitglieder auf -1. Wenn der Referenzzähler der externen Variablen zu diesem Zeitpunkt 0 ist. Dann kann es eindeutig als Müll betrachtet werden. Wenn er größer als 0 ist, wird die Anzahl der Referenzen wiederhergestellt und aus dem Garbage Collection-Pool entfernt.

Das Prinzip der Garbage Collection

Wenn Ihre Variable kein Müll ist, wird die Referenz der Gesamtvariablen nach der Reduzierung der Referenzen aller ihrer Mitgliedsvariablen um eins reduziert wird definitiv nicht 0 sein.

Beispiel

Das ist schwer zu sagen, also geben wir ein Beispiel. Als ich sf.gg zum ersten Mal durchsuchte, sah ich eine Frage zu GC und beantwortete sie. Bezüglich des GC-Garbage-Collection-Mechanismus

das Thema lautet wie folgt

Detaillierte Erklärung des PHP7-Garbage-Collection-Mechanismus

//我的回答
1、只要zval.value的refcount减一,然后缺其refcount的值不为0那么它就可能是垃圾,进入垃圾周期。
2、进入垃圾池遍历所有成员,包括其嵌套的成员,都对其做 refcount-1的操作,看外部的引用是否为0。
那么对于 题主的问题来说,
首先,你要想$a为垃圾,一定要先对 unset($a)操作,那么此时 $a的 refcount = 2
对于$a[0] refcount-1 不影响外部的$a,
$a[1] refcount-1 ,此时 $a的 refount=1
$a[2] refcount-1 ,此时 $a 的 refount=0 
模拟减结束,那么此变量被当成垃圾回收。

Das obige ist der detaillierte Inhalt vonDetaillierte Erklärung des PHP7-Garbage-Collection-Mechanismus. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen