Perl gebruikt een referentietelling algoritme voor automatisch geheugenbeheer: elke variabele heeft een referentieteller. Wanneer de teller nul wordt, wordt het geheugen vrijgegeven. In de meeste gevallen werkt dit transparant — ongebruikte variabelen worden verwijderd zodra ze uit de scope vallen.
Het probleem ontstaat met cyclische referenties (bijvoorbeeld, een object verwijst naar zichzelf of twee structuren verwijzen naar elkaar). In dat geval zal de referentieteller nooit nul worden en zal het geheugen niet worden vrijgegeven.
Om lekken te voorkomen, wordt de module Scalar::Util::weaken gebruikt — hiermee kunnen "verzwakte" referenties worden gemaakt die de referentieteller niet verhogen.
Voorbeeld:
use Scalar::Util qw(weaken); my $a = {}; my $b = { ref => $a }; $a->{ref} = $b; weaken($a->{ref}); # nu is er geen cyclische sterke afhankelijkheid
Is het correct om aan te nemen dat Perl altijd automatisch al het ongebruikte geheugen vrijgeeft, zelfs bij complexe onderling verbonden structuren?
Antwoord en voorbeeld:
Nee! In het geval van cyclische referenties kan Perl het geheugen niet automatisch vrijgeven tenzij weaken wordt gebruikt:
my $a = {}; $a->{self} = $a; # cyclus # $a zal nooit automatisch worden verwijderd — handmatige verbreking of verzwakking van de referentie is nodig
Verhaal 1: Op een grote Perl webservice was er een geheugenlek — de gebruikerssessies hielden referenties naar elkaar in een hash, en niemand gebruikte verzwakte referenties. De service verbruikte al zijn middelen binnen een dag, werd traag en vereiste herstarts.
Verhaal 2: Een zelfgeschreven ORM creëerde cycli tussen de objecten User en Group, waarbij elk naar de ander verwees. Na het verlaten van de scope bleven de objecten in het geheugen — de service "opblazen" tot tientallen gigabytes!
Verhaal 3: Gebruik van anonieme subroutines ("closures") als methodes van een klasse, die naar
$selfverwezen, leidde tot lekken bij elke creatie van een object, totdat er een analyzer verscheen die de cyclische referenties ontdekte en de noodzaak vanweakenaangaf.