2009-08-22 19 views
6

Qual è l'impatto sull'utilizzo della memoria dell'utilizzo di molti iteratori in C#? Supponiamo che un programma esegua migliaia di cicli foreach - ogni ciclo alloca un oggetto temporaneo nello heap tramite una chiamata a GetEnumerator? Il CLR esegue qualsiasi tipo di ottimizzazione (ad esempio, l'assegnazione dello stack degli oggetti IEnumerator)? O semplicemente non è un problema abbastanza significativo di cui preoccuparsi?Utilizzo memoria degli iteratori in C#

risposta

13

Nella maggior parte dei casi non è abbastanza significativo da preoccuparsi. Come sottolinea Eric, ci possono essere alcuni casi in cui è importante, ma sono piuttosto pochi e distanti nella mia esperienza.

Se stai facendo centinaia di migliaia di loop foreach, presumibilmente stai facendo lavoro effettivo all'interno di questi cicli. Quello sarà quasi certamente lontano più importante degli iteratori stessi.

Si noti che l'utilizzo di foreach su un array (noto per essere un array in fase di compilazione, ovvero) non utilizza comunque IEnumerable<T> - utilizza l'indicizzazione diretta. Non cambierei il mio codice basandomi su questo però.

Come sempre, se si è preoccupati per le prestazioni, è necessario misurarlo e profilarlo. I colli di bottiglia non sono quasi mai dove ci si aspetta che siano.

+13

Anche se questo è, come sempre, un eccellente consiglio Jon, i nostri test delle prestazioni hanno mostrato un impatto significativo sulle prestazioni dall'allocazione dell'heap/dalla raccolta dei rifiuti degli iteratori in alcuni scenari reali. Ecco perché l'enumeratore dell'elenco è un tipo di valore mutabile malvagio piuttosto che un tipo di riferimento. Ma ovviamente la frase chiave è "il nostro test delle prestazioni", come si nota, è sciocco prendere decisioni sulle prestazioni senza dati. –

+2

Ah sì, il male mutabile 'Elenco ' iteratori - Mi sembra di ricordare un post di newsgroup con quello che sembrava un ragionevole pezzo di codice ma che ha dato risultati molto strani a causa di esattamente quella decisione di progettazione :) Modificherò la risposta comunque ... le affermazioni generiche di "non è significativo" raramente sono una buona idea. –

2

Spesso il compilatore può ottimizzare un ciclo foreach in un ciclo semplice, che richiede solo una variabile di indice nello stack (o in un registro del processore).

Se si utilizza ancora un iteratore, la maggior parte di esse sono strutture, quindi vengono allocate nello stack anziché nell'heap.

I pochi iteratori delle classi sono ancora piuttosto piccoli e veloci. Potresti crearne milioni senza un impatto notevole.

+0

Suona alla grande ... Domanda di follow-up veloce: se implemento l'interfaccia IEnumerable, per definizione il metodo GetEnumerator restituisce un IEnumerator. Se il mio iteratore personalizzato è una struttura, presumo che sarebbe quindi restituito come oggetto in scatola? –

+6

Jen, _carefully_ guarda come fa la lista , e vedrai come evitare la boxe. Il trucco è che * il ciclo "foreach" in realtà non richiede che GetEnumerator restituisca IEnumerator *. Finché restituisce qualcosa che ha le giuste proprietà e metodi, sei d'oro. È quindi possibile evitare la boxing con un GetEnumerator pubblico che restituisce una struct e un IEnumerable esplicito .GetEnumerator che restituisce una struttura in scatola. –

+4

Ma ancora, come dice Jon, non fare questa cosa sciocca a meno che non si disponga di dati solidi che la creazione di enumeratori nell'heap è una delle cause principali di un problema di prestazioni che incide sul cliente e nel mondo reale. I tipi di valore mutabile causano tutti i tipi di strani problemi che sono costosi da debugare e difficili da capire. –