Basado en comentarios aleatorios de Internet, siempre he creído que el compilador de C # hace optimizaciones simples al IL (eliminando declaraciones if siempre verdaderas, inlining simple, etc.) , luego, más tarde, el JIT realiza lo real , optimizaciones complejas.

Como solo un ejemplo, en la documentación de la /optimize marca del compilador, dice

La opción / optimizar habilita o deshabilita las optimizaciones realizadas por el compilador para hacer que su archivo de salida sea más pequeño , más rápido y más eficiente.

Lo que implica que el compilador del lenguaje aplica al menos algunas optimizaciones.


Sin embargo, jugando con Prueba Roslyn, esto parece no ser cierto. Parece que el compilador de C # no hace ninguna optimización literalmente.

Ejemplos

Entrada:

bool y = true;
if (y)
    Console.WriteLine("yo");

Salida descompilada:

if (true)
{
    Console.WriteLine("yo");
}

Entrada:

static void DoNothing() { }

static void Main(string[] args)
{
    DoNothing();
    Console.WriteLine("Hello world!");
}

Salida descompilada:

private static void DoNothing()
{
}
private static void Main(string[] args)
{
    NormalProgram.DoNothing();
    Console.WriteLine("Hello world!");
}

Entrada:

try
{
    throw new Exception();
}
catch (Exception)
{
    Console.WriteLine("Hello world!");
}

Salida descompilada:

try
{
    throw new Exception();
}
catch (Exception)
{
    Console.WriteLine("Hello world!");
}

Como puede ver, el compilador de lenguaje C # parece no realizar ninguna optimización .

¿Es esto cierto? Si es así, ¿por qué la documentación afirma que /optimize hará que su ejecutable sea más pequeño?

10
BlueRaja - Danny Pflughoeft 29 ene. 2016 a las 22:00

2 respuestas

La mejor respuesta

La única optimización que se me ocurre que realiza el compilador de C # y que en realidad podrías ver con un descompilador es agregar un constructor estático vacío.

Por lo general, son bastante poco interesantes, solo IL más compactos. Solo puede verlos cuando mira el IL, un descompilador decente no lo mostrará. El código no optimizado tiene los artefactos típicos del generador de código de un compilador decente recursivo, almacenes redundantes que son seguidos inmediatamente por una carga de la misma variable, bifurca a la siguiente dirección. El optimizador sabe cómo eliminarlos. El ejemplo estándar son los NOP que se emiten para ayudar en la depuración, le permiten establecer un punto de interrupción en una llave. Eliminado por el optimizador.

Nada que proporcione una mejora de rendimiento observable fácilmente, aunque podría tener suerte de que el IL más compacto le dé al optimizador de jitter el tiempo suficiente para eliminar un almacenamiento de memoria crítico. Eso no sucede muy a menudo.

3
Hans Passant 29 ene. 2016 a las 21:26

La bandera /optimize le dice al compilador "Oye, este código intenta optimizarlo tanto como sea posible", pero esto no significa que sea la optimización de la bandera del Santo Grial.
El indicador /optimize hace muchas cosas como eliminar las variables no utilizadas, reemplazar las variables declaradas pero no utilizadas (como su ejemplo), sumar el número en el código (por ejemplo, int a = 2+2; se convierte en int a = 4; y muchas otras cosas que cand busque aquí

1
Tinwor 29 ene. 2016 a las 19:28