.Net内联函数说明

在进行JIT编译的时候,为了优化性能,会对一些方法做内联处理,MSDN上说下面这些情况不会内联:

  • IL 超过 32 字节的方法不会内联。

  • 虚函数不会内联。

  • 包含复杂流程控制的函数不会内联。复杂流程控制是除 if/then/else 以外的任意流程控制,在这种情况下,为 switch 或 while。

  • 包含异常处理块的方法不会内联,但是引发异常的方法可以内联。

  • 如果某个方法的所有定参都为结构,则该方法不会内联。

 

第一点很好理解了,之所以不让超过32字节的方法内联,是担心代码数量的膨胀。

 

虚函数不会内联。

虚函数的情形好理解,因为调用虚函数的汇编代码是这个样子的,因为虚函数是通过父类的指针调用子类的函数:

C#代码(TestMethod是一个虚函数):

 

Code Snippet
obj->TestMethod

 

 

 

 

汇编代码看起来是这样的:

 

Code Snippet

mov ecx, [obj]  --> 将obj的指针挪到寄存器里面,obj可能是一个子类的实例

add ecx, 4       --> 获取obj->TestMethod的虚函数表地址

mov eax, [ecx] --> 获取虚函数表的第一个虚函数地址,假定我们的TestMethod是第一个虚函数

call [eax]         --> 调用虚函数

 

 

 

 

 

如果我们把call [eax]给内联了,就达不到多态的目的了。

 

如果某个方法的所有定参都为结构,则该方法不会内联

我觉得这是因为结构式传值引用,在调用函数的时候,C#需要在堆栈(或者寄存器里面)分配结构的内存,并把参数内容拷贝过去,如果将定参为结构的函数都内联,可能会发生寄存器不够用的情况,那么频繁地从内存和寄存器之间传输数据已经抵消了内联带来的节省CALL和RET指令的好处。

 

包含异常处理块的方法不会内联

异常处理这玩意比较复杂,生成的CPU指令我还没怎么看过,不过不会内联应该是可以理解的,我查查资料看看。

 

为 switch 或 while

Switch也比较好理解,因为编译原理里面,switch语句的汇编指令生成算法比较复杂,一般是要创建一个排序数组来查找对应的Label的,所以不会内联也应该好理解,至于while为什么不会内联,我还真得要看看生成的汇编码。

 

我说的switch语句要生成一个排序数组的意思是,假设有一个像这样的switch语句:

 

Code Snippet

switch ( i )

{

      case 1:

              // balabala

              break;

      case 2:

              // balabala2

              break;

      default:

              // bala

              break;

}

 

 

 

 

 

生成的汇编代码类似于:

 

Code Snippet

mov eax, [i]            --> 将i的值保存到寄存器里面

// 这里只好写C#代码了,因为汇编代码我也忘记怎么写了

assembly label = BinarySearch(sortedCaseLabelArray[1, 2, ... ], eax)

// 这里是汇编代码

default: // bala

           jmp EndOfSwitch

case_1: // balabala

           jmp EndOfSwitch

case_2: // balabala2

           jmp EndOfSwitch

EndOfSwitch

          // 这里才是大括号

 

 

 

 

一般来说Switch语句都会大于32字节吧,JIT在生成代码的时候,怎么也得在JIT速度和生成代码的质量上找一个平衡的,所以一刀切是可以理解。

 

 

内联函数和lambda表达式在C中是两种不同的概念和用法。 内联函数是一种使用关键字inline定义的函数,它的主要作用是在编译器编译时将函数的代码插入到调用该函数的地方,而不是像普通函数一样进行函数调用。这样可以提高程序的执行效率,减少函数调用的开销。内联函数适用于代码比较短小、频繁调用的情况。 而lambda表达式是一种匿名定义的函数,它可以在需要的地方临时定义一个函数或函数对象。lambda表达式的语法比较简洁,可以直接写在代码中,不需要额外定义一个命名函数或函数对象。lambda表达式适用于只在某处临时调用的函数,一般与泛型算法等配合使用。lambda表达式的捕获列表可以捕获所在函数的局部变量,但仅限于非static变量。 因此,内联函数和lambda表达式在使用场景和语法上有一些差异。内联函数主要用于优化程序的执行效率,而lambda表达式主要用于简化代码的书写和提高可读性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [inline内联函数和lambda表达式的使用](https://blog.csdn.net/wangjie112358/article/details/131155222)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [inline内联函数与lambda表达式](https://blog.csdn.net/qq_31894529/article/details/112325806)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值