C# · 12月 28, 2021

c# – 为什么JIT_MethodAccessAllowedBySecurity需要这么多时间?

我正在使用一个C#应用程序,允许用户基本上导入数据表,然后以迷你语言输入自己的公式,从基础数据计算新的列.

这些公式被编译为引擎中的LINQ表达式树,然后.NET 4.0表达式树库可能会编译为IL,因此可以执行它们.

我们最近已经开始使用我们的引擎进行一些大批量滴答数据,我们发现这些编译表达式树的速度是一个真正的瓶颈 – 当快速重新计算所有这些列时,速度相当缓慢.使用内置的Visual Studio 2010分析器来显示它,其中一半的执行时间花在clr.dll中,在一个名为JIT_MethodAccessAllowedBySecurity的方法中.

这个字符串的粗略的搜索没有产生任何东西,所以我想知道有没有人可以告诉我这种方法是什么,以及是否有办法让它不要吃掉我所有的周期?也许有一种方法可以编译这个代码,明确地给它权限做任何它想要的,以便clr可以阻止这些检查?也许由表达式树引擎生成的临时程序集没有完全信任?

无论如何,我几乎感到失落,如果有任何其他StackOverflowers在过去遇到这个问题,我很有兴趣.提前致谢!

解决方法 解决方案是使用 LambdaExpression.CompileToMethod(MethodBuilder method)而不是 LambdaExpression.Compile().

我认为Jethro当时认为CAS涉及到了正确的轨道.在测试中,当我使用表达式树来调用在生成的程序集中未动态定义的函数(即使用Expression.Call来调用库方法而不是一段生成的代码)时,分析器才开始显示对JIT_MethodAccessAllowedBySecurity的调用.表明减缓是由CAS检查我生成的代码是否可以访问正在调用的方法引起的.看来,通过对我想要调用的函数应用声明式安全修改,我可以避免这种开销.

不幸的是,我无法通过使用声明性安全性(PermissionSet,SecurityAction.LinkDemand等)来摆脱JIT_MethodAccessAllowedBySecurity开销.有一点我在项目中标注了[PermissionSet(SecurityAction.LinkDemand,Unrestricted = true)]的所有方法,没有任何结果.

幸运的是,当寻找向生成的代理添加属性的方法时,我偶然发现了解决方案 – 使用MethodBuilder来编译表达式树而不是内置的LambdaExpression.Compile方法.

我已经包含了代替.Compile()的代码,并导致在计算引擎中消除了JIT_MethodAccessAllowedBySecurity调用和一个> 2x speedup:

// T must be of delegate type (Func<T>,Func<T1,T2>,etc.)public static T GetCompiledDelegate<T>(Expression<T> expr){ var assemblyName = new AssemblyName(“DelegateHostAssembly”) { Version = new Version(“1.0.0.0”) }; var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( assemblyName,AssemblyBuilderAccess.RunAndSave); var moduleBuilder = assemblyBuilder.DefineDynamicModule(“DelegateHostAssembly”,”DelegateHostAssembly.dll”); var typeBuilder = moduleBuilder.DefineType(“DelegateHostAssembly.” + “foo”,TypeAttributes.Public); var methBldr = typeBuilder.DefineMethod(“Execute”,MethodAttributes.Public | MethodAttributes.Static); expr.CompileToMethod(methBldr); Type myType = typeBuilder.CreateType(); var mi = myType.getmethod(“Execute”); // have to @R_20_2419@ to object because .NET doesn’t allow Delegates as generic constraints,// nor does it allow casting of Delegates to generic type variables like “T” object foo = Delegate.CreateDelegate(typeof(T),mi); return (T)foo;}

当使用任何使用表达式树来调用不是由Expression tree定义的函数的代码时,这个代码一直保持> 2倍.感谢大家的帮助,我希望这可以节省别人一些周期.