2010-03-15 23 views
15

Estoy desarrollando un juego usando XNA y C# y estaba tratando de evitar llamar al código de tipo new struct() en cada fotograma, ya que pensé que eso podría asustar al GC. "Pero espera", me dije, "struct es un tipo de valor. El GC no debería ser llamado entonces, ¿verdad?" Bueno, es por eso que estoy preguntando aquí.¿Qué sucede cuando se crean tipos de valores?

Solo tengo una idea muy vaga de lo que sucede con los tipos de valores. Si creo una nueva estructura dentro de una llamada a función, ¿se está creando la estructura en la pila? ¿Simplemente será empujado y reventado y el rendimiento no tendrá éxito? Además, ¿habría algún límite de memoria o implicaciones de rendimiento si, por ejemplo, necesito crear muchas instancias en una sola llamada?

Tomemos, por ejemplo, este código:

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

rectángulo en este caso es una estructura. ¿Qué sucede cuando se crea ese nuevo rectángulo? ¿Cuáles son las implicaciones de tener que repetir esa línea muchas veces (por ejemplo, miles de veces)? ¿Se crea este rectángulo, se envía una copia al método Dibujar y luego se descarta (es decir, no se consume ninguna memoria más se llama a Draw de esa manera en la misma función)?

P.S. Sé que esto puede ser una optimización pre-madura, pero tengo curiosidad y deseo tener una mejor comprensión de lo que está sucediendo.

Respuesta

4

Cuando se crea una nueva estructura, sus contenidos se colocan directamente en la ubicación donde usted especifique; si es una variable de método, va a la pila; si se asigna a una variable de clase, va dentro de la instancia de clase a la que se apunta (en el montón).

Cuando se copia una variable struct (o, en su caso, se pasa a una función), los bytes que componen la estructura se copian en el lugar correcto en la pila o dentro de la clase (si está configurando campo o propiedad en una instancia de un tipo de referencia).

Aunque puede haber copia de bytes, es probable que el compilador JIT optimice todas las copias innecesarias para que se ejecute lo más rápido posible. En general, no es algo de lo que deba preocuparse: esto es una micro-optimización :)

¿Responde a esta pregunta?

+0

Si llamo a la misma función una y otra vez, ¿se presiona un nuevo rectángulo cada llamada para Dibujar y aparece cuando devuelve Draw? – Bob

+0

Sí, pero tenga en cuenta que empujar y hacer saltar marcos de pila es simplemente incrementar/disminuir un puntero (una sola instrucción de máquina). Y el compilador JIT lo optimizará todo para que el reino llegue de todos modos. – thecoop

+0

@Bob: Sí, aunque creo que es posible, en teoría, que el JIT * pueda * ver llamadas idénticas y guardar en caché el valor para enviar varias veces, pero esto parece muy poco probable dada la heurística que implicaría detectar este y podría descartarse fácilmente. –

1

Mientras que los tipos de valores van en la pila, todavía hay implicaciones de rendimiento para asignar y desasignar toda esa memoria en cada fotograma, especialmente en la Xbox 360. En una PC, probablemente no notará la diferencia, pero en el 360 probablemente lo hará.

+0

No todos los tipos de valores van a la pila. Si c del tipo de Cliente tiene un valor tipo int edad, entonces su valor sigue en el montón. – JonH

+0

¿De verdad? ¿Sería mejor crear un nuevo rectángulo al comienzo del cuadro y reutilizarlo? – Bob

+0

La mejor opción sería intentar ejecutarlo millones de veces en ambas formas y ver cuál es más rápido. También puede comparar el IL generado para ambos métodos. – thecoop

1

Los tipos de valores se crean en la pila si se declaran localmente o en el montón si parte de una instancia de objeto (como parte de la instancia del objeto). En cualquier caso, las instancias struct no son recopiladas por el GC, se destruyen cuando su contenedor queda fuera del alcance.

El artículo MSDN struct (C#) tiene algo más de información al respecto.

1

Esto es solo para agregar a la respuesta de cofres. Para los tipos de referencia, el operador new asigna una nueva instancia del tipo en el montón y llama al constructor especificado.

Para una estructura, el operador new inicializa los campos de acuerdo con el constructor especificado. Sin embargo, es posible crear una instancia de una estructura sin usar new. En ese caso, todos los campos de la estructura no están inicializados y no pueden utilizarse hasta que no se hayan inicializado explícitamente.

Para más información, vea the description on MSDN.

Cuestiones relacionadas