为什么我的方法调用Assembly.GetCallingAssembly()不是JIT内联?(Why

2019-09-24 04:00发布

我想制作一个简短的C#代码段将说明的变化Assembly.GetCallingAssembly()因为JIT,内联行为在MSDN概述 。 这里是我到目前为止的代码:

class Program
{
   static void Main(string[] args)
   {
       Console.WriteLine( GetAssembly().FullName );
       Console.ReadLine();
   }

   static Assembly GetAssembly()
   {
       return System.Reflection.Assembly.GetCallingAssembly();
   }
}

我所要建造的“释放”,并开始使用“开始不调试” -此设置制成代码这个答案招致内联。 我看到的结果是

ConsoleApplication2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

那么清楚GetAssembly()没有联到Main() ,否则我会看到mscorlib的调用程序集。

我查看了所有的内联标准,我不明白为什么GetAssembly()不会被内联。

是它在某种程度上可能知道到底为什么JIT编译器决定不内联打个电话?

Answer 1:

这是Assembly.GetCallingAssembly()在.NET 3.5的声明:

[MethodImpl(MethodImplOptions.NoInlining)]
public static Assembly GetCallingAssembly()
{
    StackCrawlMark lookForMyCallersCaller = StackCrawlMark.LookForMyCallersCaller;
    return nGetExecutingAssembly(ref lookForMyCallersCaller);
}

该StackCrawlMark枚举有趣的是,“寻找我的来电主叫方”不能正常工作时,主叫方是要被内联。 有在其中枚举被宣布thread.cs SSCLI20源代码中的注释:

声明该枚举类型的一个局部变量和通过参考将其传递到需要做一个堆抓取都将防止卡勒[原文如此]的内联和传递一个ESP点堆叠爬行到功能

这对于GetCallingAssembly()会发生什么一个很好的匹配,这是一个局部变量,确实得到由裁判通过。 不知道该机制是什么,抖动然而生成名为CORINFO_FLG_BAD_INLINEE的方法属性。 这反过来又迫使方法描述调用:: SetNotInline()。 这是一个猜测,这是非常模糊的。



Answer 2:

为了我的两分钱添加到此。 不要依赖的东西可能 JIT做正确的有你的程序功能。

一些会从能够内联的方法禁止JIT的条件如下(摘自这里 )

  • 方法是大于32个字节IL不会被内联。
  • 虚函数不内联。
  • 有复杂的流程控制方法不会在成荫。 复杂的流控制是任何流量控制以外的if / then /别的; 在这种情况下,切换或同时。
  • 包含异常处理模块的方法没有内联,虽然抛出异常的方法仍然是内联的候选人。
  • 如果有任何的方法的形参的结构,该方法不会被内联。

正因为JIT 可以内联的方法,并不意味着它必将。 再加上在建的配置/运行/ OS组合,以及...你有它之间的行为差​​异。

在.NET 3.5 SP1 JIT的内联行为的详细信息在这里



Answer 3:

其实,你打电话给Program.GetAssembly 联到Program.Main 。 但你不能看到,因为两者的区别Program.GetAssemblyProgram.Main名为同一组件定义ConsoleApplication2

虽然可以说明的JIT内联以另一种方式:

using System;
using System.Diagnostics;

namespace A3
{
    public class Program
    {
        static void Main(string[] args)
        {
            StackFrame[] stackFrames = GetStackFrames();
            foreach (StackFrame stackFrame in stackFrames)
                Console.WriteLine(stackFrame.GetMethod().Name); // write method name

            Console.ReadLine();
        }

        //[MethodImpl(MethodImplOptions.NoInlining)]
        static StackFrame[] GetStackFrames()
        {
            StackTrace stackTrace = new StackTrace(); // get call stack
            return stackTrace.GetFrames(); // get method calls (frames)
        }
    }
}

无JIT-内联(在调试模式下,或者如果例如[MethodImpl(MethodImplOptions.NoInlining)]属性被施加到GetStackFrames )将会写入至少两行到控制台:

  1. GetStackFrames
  2. Main

但是,如果出现内联, stackFrames将只包含一个方法: Main

更新

此外,你可以在这里阅读: 调试和托管进程和Rawling在他的评论中提到:

Assembly.GetCallingAssembly()。全​​名返回取决于宿主进程是否启用不同的结果。 如果调用Assembly.GetCallingAssembly()。全​​名启用托管进程,它返回的mscorlib。 如果调用Assembly.GetCallingAssembly()。全​​名并禁止其托管进程,它返回应用程序名称。



文章来源: Why is my method calling Assembly.GetCallingAssembly() not JIT-inlined?