为什么我的方法调用Assembly.GetCallingAssembly()不是JIT内联?
我正在尝试制作一个简短的C#代码段,它将说明由于MSDN中概述的JIT内联而更改Assembly.GetCallingAssembly()
行为。 到目前为止,这是我的代码:
class Program { static void Main(string[] args) { Console.WriteLine( GetAssembly().FullName ); Console.ReadLine(); } static Assembly GetAssembly() { return System.Reflection.Assembly.GetCallingAssembly(); } }
我在“Release”中构建并开始使用“Start Without Debugging” – 这个设置使得这个答案的代码产生内联。 我看到的结果是
ConsoleApplication2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
很明显GetAssembly()
没有内联到Main()
,否则我会看到mscorlib
作为调用程序集。
我已经查看了所有内联标准,但我不明白为什么不会内联GetAssembly()
。
是否有可能知道为什么JIT编译器决定不内联调用?
这是.NET 3.5中Assembly.GetCallingAssembly()的声明:
[MethodImpl(MethodImplOptions.NoInlining)] public static Assembly GetCallingAssembly() { StackCrawlMark lookForMyCallersCaller = StackCrawlMark.LookForMyCallersCaller; return nGetExecutingAssembly(ref lookForMyCallersCaller); }
StackCrawlMark枚举很有意思,“查找我的调用者调用者”在调用者内联时无法正常工作。 在CSSCL的SSCLI20源代码中有一条注释,其中声明了枚举:
声明此枚举类型的局部变量并将其通过ref传递给需要执行堆栈爬行的函数将同时阻止内联调用[sic]并将ESP点传递给堆栈爬行到
这与GetCallingAssembly()中发生的事情非常匹配,它是一个局部变量,确实被ref传递。 不知道机制是什么,抖动可以产生名为CORINFO_FLG_BAD_INLINEE的方法属性。 这反过来强制调用MethodDesc :: SetNotInline()。 这是猜测,这是非常模糊的。
加上我的两分钱。 不要依赖JIT 可能会使程序正常运行的事情。
禁止JIT 能够内联方法的一些条件如下(取自此处 )
仅仅因为JIT 可以内联方法,并不意味着它必然会。 将它与构建配置/运行时/操作系统组合之间的行为差异结合起来,嗯……你有它。
有关.Net 3.5 SP1 JIT内联行为的更多信息,请点击此处
实际上,您对Program.GetAssembly
的调用已内联到Program.Main
。 但是你无法看到差异,因为Program.GetAssembly
和Program.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
),它将至少向控制台写入两行:
-
GetStackFrames
-
Main
但如果内联发生, stackFrames
将只包含一个方法: Main
更新
另外,正如您可以在这里阅读的那样: 调试和托管过程以及他在评论中提到的Rawling:
Assembly.GetCallingAssembly()。FullName返回不同的结果,具体取决于是否启用了托管进程。 如果在启用托管进程的情况下调用Assembly.GetCallingAssembly()。FullName,则返回mscorlib。 如果在禁用托管进程的情况下调用Assembly.GetCallingAssembly()。FullName,则返回应用程序名称。
上述就是C#学习教程:为什么我的方法调用Assembly.GetCallingAssembly()不是JIT内联?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1030241.html