使用C#编写程序,给最终用户的程序,是需要使用release配置的,而release配置和debug配置,有一个关键区别,就是release的编译器优化默认是启用的。
优化代码开关即optimize开关,和debug开关一起,有以下几种组合。
在Visual Sutdio中新建一个C#项目时,
项目的“调试”(Debug)配置的是/optimize-和/debug:full开关,
而“发布”(Release)配置指定的是/optimize+和/debug:pdbonly开关
optimize-/+决定了编译器是否优化代码,optimize-就是不优化了,但是通常,有一些基本的“优化”工作,无论是否指定optimize+,都会执行。
optimize- and optimize+该项功能主要用于动态语义分析,帮助我们更好地编写代码。
常量计算
在写程序的时候,有时能看见代码下面划了一道红波浪线,那就是编译器动态检查。常量计算,就是这样,编译器会计算常量,帮助判断其他错误。
简单分支检查
如果swtich写了两个以上的相同条件,或者分支明显无法访问到,都会弹出提示。
未使用变量
不多说明,直接看图。
使用未赋值变量
不多说,看图。
使用变量参与计算,随便写一个算式,就可以绕过一些检查,虽然我们看来是明显有问题的。
首先需要了解c#代码编译的过程,如下图:
图片来自
C# compiler将C#代码生成IL代码的就是所谓的编译器优化。先说重点。
.NET的JIT机制,主要优化在JIT中完成,编译器optimize只做一点简单的工作。(划重点)
探究一下到底干了点啥吧,以下是使用到的工具。
Tools:
Visual studio 2017 community targeting .net core 2.0
IL DASM(vs自带)
按照优化的类型进行了简单的分类。
从未使用变量 代码如下:
using System; using System.Threading.Tasks; namespace CompileOpt { class Program { static void Main(string[] args) { int x = 3; Console.WriteLine("sg"); } } }未优化的时候
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代码大小 15 (0xf) .maxstack 1 .locals init (int32 V_0) IL_0000: nop IL_0001: ldc.i4.3 IL_0002: stloc.0 IL_0003: ldstr "sg" IL_0008: call void [System.Console]System.Console::WriteLine(string) IL_000d: nop IL_000e: ret } // end of method Program::Main使用优化开关优化之后:
.method private hidebysig static void Main(string[] args) cil managed { .entrypoint // 代码大小 11 (0xb) .maxstack 8 IL_0000: ldstr "sg" IL_0005: call void [System.Console]System.Console::WriteLine(string) IL_000a: ret } // end of method Program::Main.locals init (int32 V_0)消失了(局部变量,类型为int32)
ldc.i4.3(将3推送到堆栈上)和stloc.0(将值从堆栈弹出到局部变量 0)也消失了。
所以,整个没有使用的变量,在设置为优化的时候,就直接消失了,就像从来没有写过一样。
空try catch语句 代码如下:
using System; using System.Threading.Tasks; namespace CompileOpt { class Program { static void Main(string[] args) { try { } catch (Exception) { Console.WriteLine(DateTime.Now); } try { } catch (Exception) { Console.WriteLine(DateTime.Now); } finally { Console.WriteLine(DateTime.Now); } } } }