C# de los fundamentos al dominio — Lección 9
Comprender el rendimiento con GC, tipos de valor y costos de asignación
Los artículos escritos en este blog fueron creados con el objetivo de enseñar. Además, la información del artículo puede ser incorrecta, así que tenga cuidado.
En C#, GC administra la memoria, pero los costos de asignación no desaparecen. Especialmente en programas donde es importante un tiempo de fotograma constante, como un juego, es necesario saber cuándo se crea un objeto.
Tipos de valor y tipos de referencia.
public readonly struct Damage
{
public int Value { get; }
public Damage(int value) => Value = value;
}
Damage first = new(10);
Damage second = first;
El tipo de valor contiene el valor mismo en la variable y se copia al realizar una asignación. Para los tipos de referencia, se copian las referencias que apuntan a objetos en el montón administrado.
No se limite a memorizar que los tipos de valores siempre están en la pila y que los tipos de referencia siempre son lentos. La ubicación de almacenamiento real y el costo variarán según el contexto de uso, el tamaño y la optimización del tiempo de ejecución.
evitar el boxeo
int score = 100;
object boxed = score;
int restored = (int)boxed;
El boxeo puede ocurrir cuando un tipo de valor se trata como un objeto o una interfaz implementada. Al utilizar una colección genérica, puede almacenar el tipo de valor sin cambiarlo a objeto.
var scores = new List<int>();
scores.Add(100);
Reducir las asignaciones repetidas
private readonly List<Monster> visibleMonsters = new(128);
void CollectVisible()
{
visibleMonsters.Clear();
foreach (Monster monster in monsters)
{
if (monster.IsVisible)
{
visibleMonsters.Add(monster);
}
}
}
La cantidad de asignaciones se puede reducir reutilizando un búfer con capacidad en lugar de crear una nueva lista cada vez. La concatenación de cadenas, la captura de lambdas y la generación de resultados de LINQ también pueden provocar asignaciones en la ruta de iteración.
Mida primero
Los métodos de generación y recopilación de GC son administrados por el tiempo de ejecución y los objetos de corta duración no son necesariamente un problema. La optimización previa de todo el código a expensas de la legibilidad solo puede aumentar los costos de mantenimiento.
Debe utilizar un generador de perfiles para determinar si las cuotas y las paradas son los verdaderos cuellos de botella y luego aplicar la agrupación, la reutilización del búfer y la escritura de valores. La optimización del rendimiento no es una tarea de adivinar la gramática, sino una tarea de reducir las causas de los costos medidos.