2010-03-15 12 views
15

Sto sviluppando un gioco utilizzando XNA e C# e stavo tentando di evitare di chiamare il codice di tipo new struct() ogni fotogramma come pensavo che avrebbe fatto impazzire il GC. "Aspetta," mi sono detto, "struct è un tipo di valore, quindi il GC non dovrebbe essere chiamato, giusto?" Bene, è per questo che sto chiedendo qui.Cosa succede quando vengono creati i tipi di valore?

Ho solo un'idea molto vaga di cosa succede ai tipi di valore. Se creo una nuova struttura all'interno di una chiamata di funzione, la struttura viene creata nello stack? Sarà semplicemente spinto e fatto scoppiare e le prestazioni non saranno un successo? Inoltre, ci sarebbero limiti di memoria o implicazioni sul rendimento se, per esempio, ho bisogno di creare molte istanze in una singola chiamata?

Prendete, per esempio, questo codice:

spriteBatch.Draw(tex, new Rectangle(x, y, width, height), Color.White); 

rettangolo in questo caso è una struct. Cosa succede quando viene creato quel nuovo rettangolo? Quali sono le implicazioni di dover ripetere quella linea molte volte (per esempio migliaia di volte)? Viene creato questo rettangolo, una copia inviata al metodo Draw e quindi scartata (il che significa che nessuna memoria viene mangiata più Draw viene chiamato in quel modo nella stessa funzione)?

P.S. So che potrebbe essere un'ottimizzazione pre-matura, ma sono per lo più curioso e desidero avere una migliore comprensione di ciò che sta accadendo.

risposta

4

Quando viene creata una nuova struttura, il suo contenuto viene inserito direttamente nella posizione specificata; se si tratta di una variabile di metodo, viene messa in pila; se è assegnato a una variabile di classe, va all'interno dell'istanza della classe puntata a (nell'heap).

Quando una variabile struct viene copiata (o, nel tuo caso, passata a una funzione), i byte che compongono la struct vengono tutti copiati nella posizione corretta nello stack o all'interno della classe (se stai impostando un campo o proprietà su un'istanza di un tipo di riferimento).

Anche se potrebbero esserci copie di byte, il compilatore JIT probabilmente ottimizzerà tutte le copie non necessarie in modo che vengano eseguite il più velocemente possibile. Generalmente, non è qualcosa di cui ti devi preoccupare - questo è molto più di un micro-ottimizzazione :)

Questo risponde alla tua domanda?

+0

Se chiamo ripetutamente la stessa funzione, un nuovo rettangolo ha spinto ogni chiamata a disegnare, ed è spuntato quando Draw ritorna? – Bob

+0

Sì, ma tenete presente che premendo e scoppiando fotogrammi di stack è solo incrementando/decrementando un puntatore (una singola istruzione macchina). E il compilatore JIT ottimizzerà tutto per il regno venire comunque. – thecoop

+0

@Bob: Sì, anche se immagino sia possibile - in teoria - che JIT * possa * vedere chiamate identiche e memorizzare il valore in cache per inviarlo più volte, ma ciò sembra altamente improbabile data l'euristica che sarebbe coinvolta nel rilevamento di questo e potrebbe essere facilmente escluso. –

1

Mentre i tipi di valore vanno in pila, ci sono ancora implicazioni sulle prestazioni per allocare e deallocare tutta la memoria su ogni frame, specialmente su Xbox 360. Su un PC probabilmente non noterai la differenza, ma sul 360 tu probabilmente lo farò.

+0

Non tutti i tipi di valore vanno in pila. Se c di tipo Customer ha un valore di tipo int, allora il suo valore continua a essere nell'heap. – JonH

+0

Davvero? Sarebbe meglio creare un nuovo rettangolo all'inizio del fotogramma e riutilizzarlo? – Bob

+0

La migliore scommessa sarebbe provare a eseguirla milioni di volte in entrambe le direzioni e vedere quale è più veloce. È anche possibile confrontare l'IL generato per entrambi i metodi. – thecoop

1

I tipi di valore vengono creati nello stack se dichiarati localmente o nell'heap se parte di un'istanza dell'oggetto (come parte dell'istanza dell'oggetto). In ogni caso, le istanze della struct non vengono raccolte dal GC, vengono distrutte quando il loro contenitore esce dal campo di applicazione.

L'articolo MSDN struct (C#) contiene ulteriori informazioni a riguardo.

1

Questo è solo per aggiungere alla risposta di thecoop. Per i tipi di riferimento l'operatore new assegna una nuova istanza del tipo all'heap e chiama il costruttore specificato.

Per una struttura, l'operatore new inizializza i campi in base al costruttore specificato. È tuttavia possibile creare un'istanza di una struttura senza utilizzare new. In tal caso, tutti i campi nella struct non sono inizializzati e non possono essere utilizzati fino a quando non sono stati inizializzati esplicitamente.

Per ulteriori informazioni, vedere the description on MSDN.

Problemi correlati