2009-03-10 26 views
9

Qual è l'overhead di generazione di molti oggetti temporanei (ad esempio per risultati intermedi) che "muore giovane" (mai promosso alla generazione successiva durante un intervallo di garbage collection)? Suppongo che l'operazione "nuova" sia molto economica, in quanto è solo un incremento puntatore. Tuttavia, quali sono i costi nascosti per trattare questi "rifiuti" temporanei?Oggetti di breve durata

+0

Se davvero si dispone di oggetti semplici, e soprattutto se sono facili da ripristinare, creare un pool di oggetti e riutilizzarli. Questo può funzionare anche per oggetti complicati. Una volta avevo un'app che creava migliaia di piccole bitmap per disegnare il testo interem che non poteva essere disegnato direttamente su una pagina per ragioni logiche. Per migliaia di pagine, le dimensioni sono state riutilizzate. Invece di "disporre", li ho archiviati in una tabella hash "libera" con la chiave WidthxHeight (puntato a un elenco di bitmap) e controllato prima di fare NEW. Se lì, rimuovilo, mettilo in uso. Sembra costoso, ma rendere le bitmap deve essere peggiore. Enorme velocità. – FastAl

+0

@FastAl Immagino tu intenda qualcosa come ['System.Drawing.Bitmap'] (https://msdn.microsoft.com/en-us/library/system.drawing.bitmap%28v=vs.110%29.aspx) che "incapsula una bitmap GDI +" che implica [qualcosa di simile a un syscal per creare/distruggere] (https://msdn.microsoft.com/en-us/library/windows/desktop/ms724291%28v=vs.85%29. aspx) loro. Questo è molto diverso dagli oggetti .net puri che presumo l'OP sta chiedendo. – binki

+0

@binki - Hai ragione riguardo alla bitmap, è molto più costoso, ovviamente, che gli oggetti semplici. Ma se il circuito è abbastanza stretto e non stai facendo molto con gli oggetti ... potrebbe essere comunque utile aumentare la velocità riutilizzandoli. GC deve ancora fare qualcosa. Certo in questo caso, dipende. Non menziona le dimensioni, le immagini bitmap possono essere temporanee e, come dici tu, c'è un costo nascosto per loro. I nuovi oggetti, se di grandi dimensioni, potrebbero essere cancellati prima dell'uso, se il tuo codice sovrascrive quello che c'è comunque potrebbe significare un 2x speedup (That's of ninja tho). – FastAl

risposta

12

Non molto: il garbage collector è molto veloce per gen0. Si sintonizza anche su se stesso, regolando la dimensione di gen0 in base a quanto riesce a raccogliere ogni volta che passa. (Se è riuscito a raccogliere un sacco, ridurrà la dimensione di gen0 da raccogliere in anticipo la prossima volta, e viceversa.)

Il test finale è come funziona l'applicazione . Perfmon è molto utile qui, mostrando quanto tempo è stato speso in GC, quante collezioni ci sono state di ogni generazione ecc.

+1

Downvoters: i commenti sono benvenuti, altrimenti nessuno (me compreso) saprà di cosa non sei d'accordo riguardo alla mia risposta ... –

+1

Dove posso trovare PerfMon? – Karl

+2

È quasi certamente installato già sulla tua casella di Windows. Premi Windows-R e digita semplicemente "perfmon". In caso contrario, la ricerca dipenderà dalla versione di Windows che stai utilizzando. –

3

Come dici tu l'assegnazione stessa è molto economica. Il costo di generare un sacco di oggetti a vita breve è una raccolta di rifiuti più frequente quando vengono attivati ​​quando il budget della generazione 0 è esaurito. Tuttavia, una collezione di generazione 0 è abbastanza economica, quindi finché il tuo oggetto sarà davvero di breve durata, il sovraccarico non sarà probabilmente significativo.

D'altro canto l'esempio comune di concatenare molte stringhe in un ciclo spinge il garbage collector in modo significativo, quindi tutto dipende dal numero di oggetti che si creano. Non fa male pensare all'allocazione.

Il costo della garbage collection è che i thread gestiti vengono sospesi durante la compattazione.

1

In generale, questo non è qualcosa di cui dovresti probabilmente preoccuparti e sembra che inizi a cadere molto vicino alla "micro-ottimizzazione". Il GC è stato progettato partendo dal presupposto che una "applicazione ottimizzata" avrà tutte le allocazioni in Gen0, il che significa che tutti "muoiono giovani". Ogni volta che assegni un nuovo oggetto è sempre in Gen0. Una raccolta non si verificherà fino a quando non viene superata la soglia Gen0 e non c'è abbastanza spazio disponibile in Gen0 per contenere la successiva allocazione.

L'operazione "nuovo" è in realtà un sacco di cose:

  1. l'allocazione della memoria
  2. esecuzione il tipi costruttore
  3. restituire un puntatore alla memoria
  4. incrementando il puntatore del prossimo oggetto
0

Se questi oggetti non vengono mai promossi dalla generazione 0, si vedranno prestazioni piuttosto buone. L'unico costo nascosto che riesco a vedere è che se superi il tuo budget di 0 Generazione forzerai il GC a compattare l'heap, ma il GC si auto-sintonizzerà, quindi questa non è una grande preoccupazione.

0

La raccolta dei dati obsoleti è generazionale in .Net. Oggetti di breve durata raccoglieranno prima e frequentemente. La raccolta di Gen 0 è economica, ma a seconda della scala del numero di oggetti che stai creando, potrebbe essere piuttosto costosa. Eseguirò un profiler per scoprire se sta influenzando le prestazioni. Se lo è, prendi in considerazione la possibilità di cambiarli in structs. Questi non hanno bisogno di essere raccolti.

1

Sebbene la nuova operazione sia progettata e scritta in modo efficiente, non è gratuita e richiede tempo per allocare nuova memoria. La libreria di allocazione della memoria deve tenere traccia di quali blocchi sono disponibili per l'allocazione e la memoria appena allocata viene azzerata.

La creazione di molti oggetti che muoiono giovani innescherà anche la raccolta dei rifiuti più spesso e l'operazione può essere costosa. Soprattutto con "fermare il mondo" i netturbini.

Ecco un articolo da MSDN su come funziona: http://msdn.microsoft.com/en-us/magazine/bb985011.aspx

Nota: che descrive come chiamare la raccolta dei rifiuti è costoso perché ha bisogno di costruire l'oggetto grafico prima di poter iniziare la raccolta dei rifiuti.

+0

Dall'articolo collegato: "Questi test mostrano anche che ci vuole meno di 1 millisecondo su un Pentium da 200 Mhz per eseguire un GC completo di generazione 0. È l'obiettivo di Microsoft di fare in modo che i GC non impieghino più tempo di un normale errore di pagina." IMO appena "molto costoso". Non è gratuito, certamente, ma se (cont.) –

+0

il codice è più leggibile con un sacco di oggetti piccoli, di breve durata, allora preferirei andare in quel modo finché non fosse * dimostrato * essere un collo di bottiglia di piegare il mio design fuori forma per contrastare un "problema" prestazionale che potrebbe non essere affatto un problema. –

+0

Sono d'accordo e non sto dicendo che dovrebbero cambiare il modo in cui scrivono i programmi. La domanda ha chiesto quali sono i costi generali sottostanti e ho cercato di fornire una risposta. –

Problemi correlati