Samlade cykler
Traditionellt misslyckas minnesmekanismer som använder referensräkning, såsom den som tidigare användes av PHP, med att hantera minnesläckor orsakade av cirkulära referenser. Från och med PHP 5.3.0 implementerar PHP dock den synkrona algoritmen från » [Concurrent Cycle Collection in Reference Counted Systems](https://www.hpl.hp.com/techreports/2001/HPL-2001-75.pdf), vilket adresserar detta problem.
En fullständig förklaring av hur algoritmen fungerar ligger något utanför ramen för denna sektion, men grunderna förklaras här. Först och främst måste vi etablera några grundregler. Om en refcount ökas, är den fortfarande i användning och därför inte skräp. Om refcount minskas och når noll, kan zval frigöras. Detta innebär att skräpcykler endast kan skapas när en refcount minskas till ett värde som inte är noll. För det andra, i en skräpcykel är det möjligt att upptäcka vilka delar som är skräp genom att kontrollera om det är möjligt att minska deras refcount med ett, och sedan kontrollera vilka av zvalen som har en refcount på noll.
Algoritm för skräpsamling
För att undvika att behöva kalla på kontrollen av skräpcykler vid varje möjlig minskning av en refcount, lägger algoritmen istället alla möjliga rötter (zvals) i "rotbufferten" (markerar dem "lila"). Den säkerställer också att varje möjlig skräprots endast hamnar i bufferten en gång. Först när rotbufferten är full startar insamlingsmekanismen för alla de olika zvals inuti. Se steg A i figuren ovan.
I steg B kör algoritmen en djupet-först-sökning på alla möjliga rötter för att minska refcount med ett för varje zval den hittar, och ser till att inte minska refcount på samma zval två gånger (genom att markera dem som "grå"). I steg C kör algoritmen återigen en djupet-först-sökning från varje rot nod, för att kontrollera refcount på varje zval igen. Om den finner att refcount är noll, markeras zvalen "vit" (blå i figuren). Om den är större än noll, återställs minskningen av refcount med ett med en djupet-först-sökning från den punkten, och de markeras "svart" igen. I det sista steget (D) går algoritmen över rotbufferten och tar bort zval-rötterna därifrån, och under tiden kontrollerar den vilka zvals som har markerats "vit" i föregående steg. Varje zval markerad som "vit" kommer att frigöras.
Nu när du har en grundläggande förståelse för hur algoritmen fungerar, ska vi titta tillbaka på hur detta integreras med PHP. Som standard är PHP:s skräpsamlare påslagen. Det finns dock en php.ini-inställning som tillåter dig att ändra detta: `zend.enable_gc`.
När skräpsamlaren är påslagen, körs cykelfinningsalgoritmen som beskrivits ovan när rotbufferten fylls. Rotbufferten har en fast storlek på 10 000 möjliga rötter (även om du kan ändra detta genom att ändra konstanten `GC_ROOT_BUFFER_MAX_ENTRIES` i `Zend/zend_gc.h` i PHP:s källkod och kompilera om PHP). När skräpsamlaren är avstängd, kommer cykelfinningsalgoritmen aldrig att köras. Möjliga rötter kommer dock alltid att registreras i rotbufferten, oavsett om skräpsamlingsmekanismen har aktiverats med denna konfigurationsinställning.
Om rotbufferten blir full med möjliga rötter medan skräpsamlingsmekanismen är avstängd, kommer ytterligare möjliga rötter helt enkelt inte att registreras. De möjliga rötter som inte registreras kommer aldrig att analyseras av algoritmen. Om de var en del av en cirkulär referenscykel, skulle de aldrig städas upp och skulle skapa en minnesläcka.
Anledningen till att möjliga rötter registreras även om mekanismen har inaktiverats är att det är snabbare att registrera möjliga rötter än att behöva kontrollera om mekanismen är påslagen varje gång en möjlig rot kunde hittas. Skräpsamlings- och analysmekanismen själv kan dock ta avsevärd tid.
Förutom att ändra konfigurationsinställningen `zend.enable_gc`, är det också möjligt att slå på och av skräpsamlingsmekanismen genom att anropa `gc_enable()` respektive `gc_disable()`. Att anropa dessa funktioner har samma effekt som att slå på eller av mekanismen med konfigurationsinställningen. Det är också möjligt att tvinga insamling av cykler även om den möjliga rotbufferten ännu inte är full. För detta kan du använda funktionen `gc_collect_cycles()`. Denna funktion kommer att returnera hur många cykler som samlades in av algoritmen.
Anledningen bakom möjligheten att slå på och av mekanismen, och att initiera cykelinsamling själv, är att vissa delar av din applikation kan vara mycket tidskritiska. I dessa fall kanske du inte vill att skräpsamlingsmekanismen ska aktiveras. Naturligtvis, genom att stänga av skräpsamlingen för vissa delar av din applikation, riskerar du att skapa minnesläckor eftersom vissa möjliga rötter kanske inte får plats i den begränsade rotbufferten. Därför är det troligen klokt att anropa `gc_collect_cycles()` precis innan du anropar `gc_disable()` för att frigöra minnet som kan gå förlorat genom möjliga rötter som redan är registrerade i rotbufferten. Detta lämnar då en tom buffert så att det finns mer utrymme för att lagra möjliga rötter medan cykelinsamlingsmekanismen är avstängd.
Sidslut
Orginalhemsidan på Engelska :https://www.php.net/manual/en/features.gc.collecting-cycles.php PHP
Det här är en maskinöversättning av PHP-manualen till svenska. Om du hittar fel är vi tacksamma om du rapporterar dem via formuläret som finns på
https://www.linux.se/kontaka-linux-se/
Tack till Datorhjälp.se som har sponsrat Linux.se med webserver.