2015-08-14 16 views
10

Ho chiesto di recente a question di sovrascrivere gli oggetti e la gestione della memoria in Perl. Una delle risposte che ho ricevuto mi ha segnalato che potrei avere un problema con uno script che ho scritto di recente.Prevenzione di perdite di memoria di riferimento cicliche in Perl

Ho uno script con alcune strutture di dati molto complesse che hanno molte relazioni parent->child/child->parent. Ciò significa anche che ci sono molti oggetti con riferimenti ciclici. Secondo this answer, i riferimenti ciclici possono "ingannare" il meccanismo di conteggio dei riferimenti di Perl e causare perdite di memoria se non vengono gestiti correttamente.


Esempio di un riferimento ciclico:

 +-----------------------------------------------------+ 
     |              | 
     +-->+============+ +==========+     | 
      [ Reference ----->[ Blessed ]     | 
$parent -->+============+ [ Hash  ]     | 
          [   ] +==========+  | 
          [ children --->[ Array ]  | 
          [   ] [   ]  | 
          +==========+ [ 0: ---------+ | 
              [   ] | | 
              +==========+ | | 
                  | | 
     +--------------------------------------------------+ | 
     |              | 
     +-->+============+ +==========+     | 
      [ Reference ----->[ Blessed ]     | 
$child --->+============+ [ Hash  ]     | 
          [   ]     | 
          [ parent: ----------------------+ 
          [   ] 
          +==========+ 

(Disclaimer - questa non è la mia arte epica - Grazie @Ikegami per questo diagramma ASCII dolce!)

Problema: Ogni oggetto ha un riferimento all'altro. . . ciò significa che una volta che $parent e $child escono dall'ambito, il contatore di riferimento di Perl continua a pensare che esista un riferimento a ciascun oggetto in modo che la memoria non venga mai liberata. Si finisce con due oggetti in memoria senza possibilità di accedere ai dati di nessuno di loro!


La mia domanda è: Qual è il modo corretto di affrontare i riferimenti ciclici al fine di garantire il Perl gestisce la sua pulizia correttamente? Come ci si assicura che Perl non lasci tracce quando tutti i riferimenti esterni ad un oggetto autoreferenziale vengono eliminati?

+2

Per quanto riguarda l'opera epica: http://asciiflow.com/ – simbabque

+0

Algebrico !!!!!! – tjwrona1992

+3

Ne parliamo in [Intermediate Perl] (http://www.intermediateperl.com) quando creiamo un registro oggetti per tenere traccia di tutti gli animali nel nostro esempio da cortile. :) –

risposta

12

Scalar::Util e in particolare la funzione weaken.

L'lvalue $ ref verrà trasformato in un riferimento debole. Ciò significa che non manterrà un conteggio dei riferimenti sull'oggetto a cui fa riferimento. Anche quando il conteggio dei riferimenti su quell'oggetto raggiunge lo zero, il riferimento sarà impostato su undef. Questa funzione modifica l'lvalue passato come argomento e non restituisce alcun valore.

Imposta uno o entrambi i riferimenti come "deboli" e la catena a margherita si svela automaticamente quando le ancore vengono distrutte.

+2

Cool Ci provo. Vorrei sapere di questo circa un mese fa ... Ho molti riferimenti da indebolire! – tjwrona1992

+0

Hmm ci possono ancora essere alcuni problemi con questo a seconda di come gli oggetti vengono utilizzati ... (vedi [qui] (http://stackoverflow.com/questions/32013133/can-using-scalarutils-weaken-cause-invalid- problemi di riferimento)) Ma nel complesso questo risolve il problema principale della perdita di memoria, quindi ho selezionato questa risposta. – tjwrona1992