防止JIT内联方法

我有一种独特的情况。 我一直在开发一个用于发送电子邮件的开源库。 在这个库中,我需要一种可靠的方法来获取调用方法。 我通过分析StackFrame里面的StackFrame对象完成了这个。 这在没有关闭优化的调试模式项目中没有问题。

当我切换到启用优化的发布模式时,会发生此问题。 堆栈跟踪如下所示:

 > FindActionName at offset 66 in file:line:column :0:0 > Email at offset 296 in file:line:column :0:0 > CallingEmailFromRealControllerShouldFindMailersActionName at offset 184 in file:line:column :0:0 > _InvokeMethodFast at offset 0 in file:line:column :0:0 > InvokeMethodFast at offset 152 in file:line:column :0:0 ... 

这是从失败的unit testing中获得的。 在这个跟踪的第3行,我应该看到一个名为TestEmail的方法,它在别处定义,但我相信JITter正在内联它。 我已经读过你可以通过使方法虚拟来防止内联,但这不起作用。 有没有人知道一种可靠的方法来防止方法内联,所以你的方法会出现在堆栈跟踪中?

您可以使用MethodImplAttribute并指定MethodImplOptions.NoInlining

 [MethodImpl(MethodImplOptions.NoInlining)] void YourMethod() { // do something } 

请注意,这仍然不能保证您可以获得源代码中看到的实际调用方法。 您的方法不会内联,但您的方法的调用者可以内联到自己的调用者等等。

您可以使用标记为System.Runtime.CompilerServices.CallerMemberNameAttribute其他参数以及它的兄弟CallerFilePathCallerLineNumber 。 如果我理解正确的话,这应该会为您提供正确的方法名称,无论内容是什么都没有。 你只会得到方法名称,我没有看到任何东西来获得类名/汇编等。

应该不言而喻,但只是为了确定……这样的事情应该在日志记录/诊断之外使用。

正确的方法可能是:

  • 将所需信息作为参数传递
  • 在调用函数时临时将所需信息存储在Thread.ExecutionContext

我意识到这可能对斯科特没有任何帮助,但也许其他人可以从中受益。

Interesting Posts