2012-02-18 17 views
6

ya que nuevas instancias de los tipos de valor se crean cada vez que se pasan como argumentos, empecé a pensar en escenarios en los que utilizan los ref o out palabras clave pueden mostrar una mejora sustancial del rendimiento.¿Beneficio de los tipos de valor sobre los tipos de referencia?

Después de un tiempo me di cuenta que mientras veo el déficit de la utilización de los tipos de valor que no sabía de ninguna ventaja.
Así que mi pregunta es bastante simple: ¿cuál es el propósito de tener tipos de valores? ¿Qué ganamos copiando una estructura en lugar de simplemente crear una nueva referencia a ella?

Me parece que sería mucho más fácil tener sólo los tipos de referencia como en Java.

Editar: Sólo para aclarar esto, no me refiero a los tipos de valor menor que 8 bytes (tamaño máximo de una referencia), sino más bien los tipos de valores que son 8 bytes o más. Por ejemplo, la estructura Rectangle que contiene cuatro valores int.

+0

¿Realmente Java solo tiene tipos de referencia? –

+5

¿Cuántos bytes ocupa una matriz de un millón de bytes si son tipos de valor? ¿Cuántos ocupa si son tipos de referencia? –

+0

Sí. Esto en realidad surge a veces como un problema. Incluso DateTime es un objeto. – usr

Respuesta

12
  • Una instancia de un tipo de valor de un byte ocupa un byte. Un tipo de referencia ocupa el espacio para la referencia más el bloque de sincronización y la tabla de funciones virtuales y ...

  • Para copiar una referencia, copie una referencia de cuatro (u ocho) bytes. Para copiar un entero de cuatro bytes, copie un entero de cuatro bytes. Copiar tipos de valores pequeños no es más costoso que copiar referencias.

  • Los tipos de valor que no contienen referencias no necesitan ser examinados por el recolector de basura en absoluto. El recolector de basura debe rastrear cada referencia.

+1

La localidad de referencia también es un GRAN negocio. –

+0

Debería haber dejado en claro de inmediato, pero me refería a los tipos de valores que son más grandes que el tamaño de una referencia. Acerca de su tercer punto: no es una referencia local de método descartada automáticamente cuando finaliza el método; lo mismo que una estructura? – Acidic

+0

@Acidic: seguro, la * referencia * está descartada. Pero * lo referido a * puede no ser; algo más podría estar refiriéndolo. –

3

"Creación de una referencia" no es el problema. Esto es solo una copia de 32/64 bits. Crear el objeto es lo que es costoso. En realidad, crear el objeto es barato, pero no es recopilarlo.

tipos de valor son bueno para el rendimiento cuando son pequeños y se desecha a menudo. Se pueden usar en arreglos enormes de manera muy eficiente. Una estructura no tiene encabezado de objeto. Hay mucho de otras diferencias de rendimiento.

Editar: Eric Lippert fue un gran ejemplo en los comentarios: "¿Cuántos bytes ocupa una matriz de un millón de bytes si son tipos de valor? ¿Cuántos ocupan si son tipos de referencia?"

I responderá: Si el embalaje struct se establece en 1 tal matriz se llevará a 1 millón y 16 bytes (en el sistema de 32 bits). El uso de los tipos de referencia que tomará:

array, object header: 12 
array, length: 4 
array, data: 4*(1 million) = 4m 
1 million objects, headers = 12 * (1 million) 
1 million objects, data padded to 4 bytes: 4 * (1 million) 

Y es por eso que el uso de los tipos de valor en grandes matrices puede ser una buena idea.

2

La ganancia es visible si sus datos son pequeños (< 16 bytes), tiene muchas instancias y/o las manipula mucho, especialmente al pasar a funciones. Esto se debe a que la creación de un objeto es relativamente costosa en comparación con la creación de una instancia de tipo de valor pequeño. Y como alguien más señaló, los objetos deben ser recolectados y eso es aún más costoso. Además, los tipos de valores muy pequeños toman menos memoria que sus equivalentes de tipo de referencia.

Ejemplo de tipo de valor no primitivo en .NET es estructura de puntos (System.Drawing).

2

tipos de valor son por lo general con más prestaciones que los tipos de referencia: los costos de tipo

  • una referencia a memoria adicional para la referencia y el rendimiento cuando dereferencing

  • un tipo de valor no necesita basura adicional colección. Recoge la basura junto con la instancia en la que vive. Las variables locales en los métodos se limpian al salir del método.

  • Las matrices de tipo de valor son eficientes en combinación con cachés. (Piense en una matriz de enteros en comparación con una variedad de casos de tipo Integer)

1

Cada variable tiene un ciclo de vida. pero no todas las variables necesitan la flexibilidad para que su variable tenga un alto pero no se gestione en el montón.

Los tipos de valor (Struct) contienen sus datos asignados en la pila o asignados en línea en una estructura. Los tipos de referencia (Clase) almacenan una referencia a la dirección de memoria del valor y se asignan en el montón.

¿cuál es el propósito de tener tipos de valores? tipos de valor son muy eficientes para manejar datos simples, (Cabe uso para representar tipos inmutables para representar valor)

valor Tipo objetos no pueden ser asignados en el montón de basura recogida, y la variable que representa el objeto no contiene un puntero a un objeto; la variable contiene el objeto mismo.

¿Qué obtenemos copiando una estructura en lugar de simplemente crear una nueva referencia a ella?

Si copia una estructura, C# crea una nueva copia del objeto y asigna la copia del objeto a una instancia de estructura separada. Sin embargo, si copia una clase, C# crea una nueva copia de la referencia al objeto y asigna la copia de la referencia a la instancia de clase separada. Las estructuras no pueden tener destructores, pero las clases pueden tener destructores.

+0

gracias oleksii, para editar, aplausos, T –

1

Una ventaja importante de los tipos de valor como Rectangle es que si uno tiene n lugares de almacenamiento de tipo Rectangle, uno puede estar seguro de que uno tiene n casos distintos de tipo Rectangle. Si uno tiene una matriz de tipo Rectangle, de longitud al menos dos, una declaración como MyArray[0] = MyArray[1] copiará los campos de MyArray[1] en los de MyArray[0], pero continuará para referirse a distintas Rectangle casos. Si se realiza una línea de declaración MyArray[0].X += 4 que modificará el campo X de una instancia, sin modificar el valor X de ninguna otra ranura de matriz o instancia Rectangle. Tenga en cuenta, por cierto, que la creación de la matriz se rellena instantáneamente con instancias Rectangle escribibles.

Imagine si Rectangle era un tipo de clase mutable.Crear una matriz de instancias mutables Rectangle requeriría que una primera dimensión la matriz, y luego asignar a cada elemento en la matriz una nueva instancia Rectangle. Si uno quisiera copiar el valor de una instancia de rectángulo a otra, tendría que decir algo como MyArray[0].CopyValuesFrom(MyArray[1]) [que, por supuesto, fallaría si MyArray[0] no se hubiera llenado con una referencia a una nueva instancia). Si se dijera accidentalmente MyArray[0] = MyArray[1], escribir en MyArray[0].X también afectaría a MyArray[1].X. Cosas desagradables.

Es importante tener en cuenta que hay algunos lugares en C# y vb.net donde el compilador copiará implícitamente un tipo de valor y luego actuará sobre una copia como si fuera el original. Este es un diseño de lenguaje realmente desafortunado y ha llevado a algunas personas a plantear la proposición de que los tipos de valores deberían ser inmutables (ya que la mayoría de las situaciones que involucran copias implícitas solo causan problemas con los tipos de valores variables). Cuando los compiladores eran muy malos al advertir sobre casos en los que las copias dudosas desde el punto de vista semántico arrojaban comportamientos rotos, tal idea podía ser razonable. Sin embargo, debería considerarse obsoleto, dado que cualquier compilador moderno decente señalará errores en la mayoría de los escenarios donde la copia implícita arrojaría semánticas rotas, incluyendo todos los escenarios donde las estructuras solo se mutan a través de constructores, definidores de propiedad o asignaciones externas a campos públicos mutables . Una declaración como MyArray[0].X += 5 es mucho más legible que MyArray[0] = new Rectangle(MyArray[0].X + 5, MyArray[0].Y, MyArray[0].Width, MyArray[0].Height).

Cuestiones relacionadas