14

Date un'occhiata a questa parte un mucchio un'istantanea Chrome:Chrome/V8 non raccoglie i dati di riferimento circolari?

Chrome circular reference

mostra i fermi di un oggetto nel mucchio che, per quanto ne so e posso vedere, dovrebbe essere spazzatura, ma è non raccolto nonostante ciò.

Il percorso "più breve" alla radice è, dopo tutto, un percorso ciclico (non raggiunge mai effettivamente la radice). Il che lascia uno stupore, in che modo il visualizzatore di foto istantanee è persino in grado di assegnargli una distanza di 12? È solo il numero di passaggi necessari per completare il ciclo prima di arrendersi? Nota come la distanza non arriva mai al di sotto 11.

Ho letto che può richiedere alcune iterazioni per pulire sottografi con riferimenti circolari. Ma le raccolte forzate ripetute (con il pulsante del cestino nella scheda Timeline) non riuscivano a ripulire questi oggetti.

Si noti che l'esplorazione tramite i riferimenti "185" alla fine porta allo stesso system/Context @862399, quindi non c'è davvero un percorso dalla radice a questo oggetto (almeno non visibile qui).

Sto impazzendo, o il netturbino è effettivamente rotto? Non ricordo di aver avuto questo problema in passato. Sono su Chrome 45.0.2454.101. La beta 46.0.2490.64 si comporta allo stesso modo.

+0

Questi metodi sono persino in grado di essere raccolti? Stai creando chiusure? Potresti inavvertitamente creare una perdita di memoria? – Jesse

+0

La [Guida di stile JavaScript di Google] (https://google.github.io/styleguide/javascriptguide.xml?showone=Closures#Closures) ha un esempio di chiusura che crea un riferimento circolare che genera una perdita di memoria. Se questo è il caso dell'OP, non è una novità: [1] (http://stackoverflow.com/questions/19550253), [2] (http://stackoverflow.com/questions/16442201), [3 ] (http://stackoverflow.com/questions/11186750). Non so perché, ma i moderni motori JS non sembrano avere una soluzione per affrontare questa fonte molto comune di perdite di memoria. –

+0

@ GOTO0 Sono consapevole che una chiusura mantiene i riferimenti alle variabili che utilizza (come potrebbe funzionare diversamente?) Ma che mantiene anche variabili di inclusione non utilizzate è nuova per me, e in realtà piuttosto deludente. Tuttavia, quella guida di stile dice "un riferimento circolare e quindi una perdita di memoria". Non è un'affermazione obsoleta che si applica solo al conteggio dei riferimenti GC? Pensavo che mark-and-sweep avrebbe dovuto rendere questo un non-problema? E se quella parte è sbagliata, il resto di questa guida è affidabile? –

risposta

1

Per essere completamente onesti, è necessario un rapido sguardo al codice di prova in cui è stato replicato, ma ho un'idea generale di ciò che si sta verificando. Se ho torto e puoi fornire un codice di prova che lo provi, ti prego di farmelo sapere.

Come sembra già sapere, per 'ripulire', Javascript non vuole più riferimenti all'elemento che vuole essere liberato.

Un semplice esempio:

// Currently not eligible for garbage 
var myObj = { 
    data : 'test' 
}; 

// Reference data inside myObj 
// A unique identifier to myObj.data now exists 
var myData = myObj.data; 

// Whoops 
myObj = 'something else'; 

// Because myData exists, so does data and can not be freed either, understandable 
// This sounds simple and logical but most do not understand what is happening in the engine 
// A relationship has been born between 'myData' and 'data' and as long as it exists, it is not eligible for garbage and remains in memory 
console.log(myData); 

Il codice è probabilmente più complicato di questo, ma questo potrebbe aiutare a spiegare come, da qualche parte, l'immondizia non può essere raccolto come la catena di portata può essere seguito a un riferimento.

consideri il seguente

function oops(text){ 

    function doStuff(){ 
     return text.toLowerCase(); 
    } 
    return doStuff(); 
} 

// 'doStuff' stays alive thanks to 'test' below. 
var test = oops('closure'); 

la funzione doStuff non saranno spazzatura collezionati perché viene fatto riferimento da test.

// You can see where this is headed. We have 2 references to the same 'doStuff' function object with separate unique identifiers now below. 
var test2 = oops('closures...'); 

// This is now another unique identifier to 'doStuff' 
var test3 = test2; 

// doStuff survives yet still 
test = 0; 
test2 = 0; 

// Now we let the function object of 'doStuff' be freed because there is no longer any references to it 
test3 = 0; 

Questa è essenzialmente una perdita di memoria che abbiamo creato. Ogni volta che si chiama oops si sta creando un oggetto funzione doStuff con un identificativo univoco.

un modo per evitare che questo potrebbe essere

function doStuff(text){ 
    return text.toLowerCase(); 
} 

function oops(text){ 
    return doStuff(); 
} 

var test = oops('closure'); 

ora non abbiamo perdite di memoria. doStuff è invocato e non creato.

Uno sguardo più da vicino al codice e troverete che probabilmente lo state facendo da qualche parte.

Se hai problemi con gli elementi e penso che potresti essere, IBM has a good article about circular references potresti voler dare un'occhiata.


E 'tardi e alcuni di questo è stato testato, ma la teoria è ancora lì, quindi se ho scritto male qualcosa, ecc, fatemelo sapere e vi posso dare un'occhiata domani per i futuri visitatori di questa pagina.

+0

Grazie per la tua risposta , ma come detto sopra, ero già consapevole del potere di conservazione delle chiusure, anche se apparentemente non del tutto. Tuttavia, se i valori nell'istantanea del mio heap sono raggiungibili da una radice GC, perché non c'è un percorso completo mostrato con una distanza decrescente fino a 1? Questo significa che il visualizzatore di istantanee in realtà non è affidabile? E come detto nella domanda, non ho riscontrato questo problema in passato (anche se è difficile dire se sia stata apportata una modifica all'app o a Chrome). –

+0

Ho provato a riprodurre il problema nel codice di esempio, ma non ci sono riuscito. Va detto che la vera applicazione in cui si verifica è piuttosto grande, essendo un gioco di una sola pagina considerevole.L'utilizzo della memoria (prima delle perdite) può raggiungere diverse centinaia di mega. Non so se il browser sia ancora pronto per questo? –

+0

Certo, i browser possono gestire alcune centinaia di meg se l'utilizzo della memoria è giustificato, ma maggiore è la memoria e maggiore è la latenza. Se posso raccomandare qualcosa. Fai un'istantanea, usa la tua applicazione per un po 'e prendine un'altra e confronta. Con gli elementi dom puoi trovare i posti da ottimizzare come la persona ha fatto in questo articolo: https://blog.newrelic.com/2012/07/17/using-chrome-developer-tools-to-find-memory-leaks/ – Jesse