Pregunta

Sé que el boxeo es un concepto popular con mucha información disponible, pero tengo algunas preguntas que realmente no puedo encontrar respuestas a:

1) Si el boxeo lleva a que un tipo de valor (estructura) se convierta en un objeto (Tipo de referencia), o tipo de referencia, ¿por qué usar un tipo de valor que será encajonado e incurrirá en una penalización de rendimiento? Soy consciente de los beneficios y la idoneidad en ciertos casos de una estructura o clase. Se dice (1) que los valores (tipos de valores) tienden a vivir en la pila en un espacio de almacenamiento temporal, pero ¿por cuánto tiempo? Si no necesito el tipo, ¿cómo puedo asegurarme de que se cuide y deseche en ese momento? ¿O es aquí donde entra en juego el patrón desechable? Supongo que la razón para usar una estructura se debe a sus beneficios.

Curiosamente, si utilizo una estructura para almacenar dos cadenas y un campo Fecha y hora, la estructura tendrá dos referencias (cadenas) y la Fecha y hora juntas. Obviamente, asumo que esto es más rápido que los valores que se dispersan. ¿Hay algo que deba tener en cuenta en este diseño? (2).

1) http: //en.csharp-online .net / Clases, Estructuras y Objetos: Boxeo y Desembalaje

2) http://dotnetperls.com/Content/Struct-Examples.aspx

He hecho una búsqueda aquí de las respuestas que busco, pero no tengo suerte. Generalmente hago búsquedas en este sitio para temas como GC, genéricos, manejo de excepciones, etc., ya que hay mucha sabiduría para aprender y compartir.

¡Gracias por la educación (potencial) para todos los carteles! Por favor, disculpe cualquier ingenuidad potencial. Aprender los aspectos internos me lleva bien a dedicar algo de tiempo a comprender IL, etc. (algo que abordar, pronto).

¿Fue útil?

Solución

Si nunca pasa el tipo de valor a una variable de referencia, entonces no ocurrirá el boxeo. Cuando no lo sepa, responda las siguientes preguntas :

  • Actúa como tipos primitivos.
  • Tiene un tamaño de instancia inferior a 16 bytes.
  • Son inmutables.
  • La semántica de valor es deseable.

Por lo general, también considero cuál es el tiempo de vida de dicha variable. Si se trata de una variable local utilizada dentro de un método, trataría de usar struct (de lo contrario, clase).

Otros consejos

Debe usar tipos de valor debido a su beneficio lógico, no a las ganancias de rendimiento. Dicho esto, dado que los tipos de valor se administran en la pila, no es necesario que participen en la recolección de basura. Si tiene un tipo que se crea y descarta constantemente (como un int, float, double, etc.), puede obtener un buen impulso convirtiéndolos en estructuras. Lo que hay que tener cuidado es que solo deberías considerar esto si también puedes hacer que la estructura sea inmutable.

Un par de otras cosas a considerar -

Primero, desea asegurarse de que las estructuras son inmutables (en general). Debido a esto, es una buena regla general no tener estructuras que contengan tipos de referencia. Las cadenas pueden ser una excepción a esto, ya que son inmutables en C #, pero en términos de una regla general de uso general para el diseño, desconfiaré de esto.

Segundo, hay otro caso de uso para estructuras que no se mencionó hasta ahora: grandes cantidades de objetos pequeños. Si tiene una lista grande o una matriz de objetos pequeños, las estructuras proporcionan una coherencia de caché dramáticamente mejor y son absolutamente críticas. Esta es la razón por la que la mayoría de los motores 3D utilizan estructuras para puntos / vectores: tienden a tener grandes matrices de puntos para vértices, etc.

Esto es algo a lo que vale la pena prestarle atención si el rendimiento es una parte importante de su aplicación. Por ejemplo, en una de mis aplicaciones, el cambio de un solo tipo de una clase a una estructura se redujo en un 40% en un proceso de larga ejecución (> 5 minutos de ejecución). Tener los objetos juntos en la memoria si los usa repetidamente en cálculos matemáticos pesados ??puede proporcionar grandes ganancias.

Ahora, en su caso, tener 2 cadenas y un DateTime probablemente no verá ninguna mejora de esto. El tipo de rutinas que funcionaría en cadenas probablemente no esté haciendo un cálculo pesado (con suerte), es decir: transformando medio millón de puntos en el espacio, o haciendo una solución de matriz grande, etc.

Finalmente, notará que .net3.5sp1 hizo que las estructuras fueran mucho más útiles. Antes de 3.5sp1 (en x86), no había ninguna incorporación de métodos con llamadas a estructura. Esto limitó las ganancias de rendimiento posibles a través de estructuras. La actualización de su marco puede hacer que el código de estructura anterior sea mucho más rápido (en ciertos casos).

No siempre se necesita boxeo, y con los genéricos no hay necesidad de eso.
La memoria utilizada por los tipos de valor (struct es un tipo de valor) se reclamará como
tan pronto como el método finalice / regrese y no tenga que hacer nada para que eso suceda.

Los tipos de valor declarados como miembros de la instancia estarán en la memoria hasta que el objeto
es eliminado por el GC.

Los tipos de referencia se mantienen en el montón administrado.
Los tipos de referencia instanciados dentro de un método serán eliminados por el
recolector de basura cuando ningún objeto contiene una referencia a él.

GC funciona por sí solo y, en su mayor parte, debería dejarlo solo.
No se puede predecir cuándo un GC va a eliminar un objeto.

El patrón de Disposición se usa en los tipos de referencia, pero no obligará a que GC elimine
un objeto. Generalmente se usa para liberar recursos no administrados.

Para los valores en la pila, considere lo siguiente:
Digamos que tienes un programa simple con tres métodos, como a continuación:
Cuando se ejecuta este programa, se ejecuta el método Main, y así sucesivamente. Por favor siga el
números a continuación:


Main
{
   // (0) Stack is empty
   int firstInt = 0;
   // (1) Stack now contains:
   //                     firstInt
   DoSomething1();
   // (7) Stack still contains:
   //                     firstInt
}
// Program ends

DoSomething()
{
   int anInteger = 0; 
   // (2) Stack now contains:
   //                    anInteger
   //                    firstInt
   DoMore()
   // (5) Stack now contains:
   //                     anInteger
   //                     firstInt
}
// (6) anInteger goes out of scope

DoMore
{
  int anotherInteger = 1; 
   // (3) Stack now contains:
   //                     anotherInteger
   //                     anInteger
   //                     firstInt
}
// (4) anotherInteger goes out of scope

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top