2013-03-29 18 views
10

Ho riscontrato un problema con la garbage collection in Ruby, in cui un oggetto che ritengo dovrebbe essere garbage collection non viene raccolto automaticamente.Collezione Garbarge in Ruby con riferimenti a oggetti circolari

require 'ruby-mass' 

def find_dependencies(_object_id,_mapped = {}) 
    mapped = _mapped 
    points_to_object = Mass.references(Mass[_object_id]) 
    ids = points_to_object.keys.map{|x| /\#(\d*)/.match(x).captures.first.to_i} 
    mapped[_object_id] = ids 

    unmapped = ids - mapped.keys 
    unmapped.each do |x| 
    new_deps = find_dependencies(x,mapped) 
    mapped.merge(new_deps) 
    end 
    mapped 
end 

Fare alcune cose che rendono gli oggetti e trovare l'ID oggetto pertinente. GC.start, quindi:

> find_dependencies(144789180) 
=> {144789180=>[61895480, 144786340, 147807540], 
61895480=>[144789180], 
144786340=>[144789180], 
147807540=>[144789180]} 

Sembra che ci sia un modello di riferimento circolare qui, ma è tutto completamente contenuto in questi quattro oggetti, in modo che il collettore di Mark-and-sweep dovrebbe trovarli e rimuoverli.

Quindi, c'è un bug nella mia find_dependencies_function, la gemma di massa o il garbage collector di Ruby. Come posso restringere questo verso il basso per scoprire qual è il problema e risolvere questa perdita di memoria?

+3

Mark-and-sweep non può gestire questo genere di cose. Per fare ciò, devi usare WeakRef in quegli oggetti per consentire al raccoglitore di rimuovere l'intero albero. – Linuxios

+0

Perché non è possibile contrassegnare e spazzare gestire queste cose? Posso vedere come potrebbero passare attraverso il conteggio dei riferimenti, ma questi non dovrebbero essere contrassegnati, e dovrebbero essere raccolti, no? – aaronjg

+0

Prima devo chiedere - come si perde il riferimento all'oggetto? Ci sono assolutamente * no * altri riferimenti ai sottooggetti? – Linuxios

risposta

2

Il GC in Ruby lavora essenzialmente in questo modo:

  1. Mark tutti gli oggetti globali come dal vivo.

  2. Spazzare gli oggetti, raccogliere i rifiuti a meno che un genitore non sia in vita.

Così, nel caso di un riferimento circolare, A trattenendo B trattenendo A otterrebbe GC'd poiché né si svolge da un oggetto vivo.

Per i commenti, c'è qualcosa che non necessariamente in possesso sull'oggetto da qualche parte ... O forse Mass sta recuperando RangeError o qualcosa del genere ...

>> a = {} 
=> {} 
>> a[:a] = a 
=> {:a=>{...}} 
>> a.object_id 
=> 2269556540 
>> a = nil 
=> nil 
>> GC.start 
=> nil 
>> ObjectSpace._id2ref(2269556540) 
RangeError: 0x8746af3c is recycled object 
    from (irb):17:in `_id2ref' 
    from (irb):17 
Problemi correlati