.NET Release code very slow when running a method for the first time. How to fix it withough NGen?

烂漫一生 提交于 2019-12-19 04:09:30

问题


I have deployed a application in release mode (x64) which I expected to be fast, and I noticed that there is a severe slowdown whenever a new method, or set of methods is executed for the first time. When I say severe I mean 100-200 ms to execute the first time and it takes well under 1 ms after that.

From what I found, this seems to be due to the JIT compiler which is supposed to compile methods the first time they are run. I expected some delay from this, but 100 ms is a disastrous delay in the middle of execution.

I know about NGen, but NGen needs to be done at install time on the machine. The machines this is for all have limited user rights and cannot install anything. The app is deployed as an executable and reference DLLs. I think that is why I could never get NGen to work.

Is there any way to make the JIT to compile every method at start up?

I though of creating dummy variables and adding a start-up routine that would do nothing but run every method once so it can be what when start-up completes. Would that be sufficient to force a compile or does every code path of a method need to be executed separately.


回答1:


Wow. Such delays are unusual for the JIT. Profile your app to make sure the bottleneck is the JIT.

Now, if it's really the JIT, here's a much better method than adding a dummy argument everywhere:

Use RuntimeHelpers.PrepareMethod on each non-generic method. This function will force the JIT to process it.

You can also use RunClassConstructor method on each class to... well, run their static constructors.

Here's some (totally untested) code:

foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
{
    if (type.IsGenericTypeDefinition || type.IsInterface)
        continue;

    RuntimeHelpers.RunClassConstructor(type.TypeHandle);

    foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly))
        RuntimeHelpers.PrepareMethod(method.MethodHandle);
}



回答2:


NGen should be run on each machine at install time. Make it part of your install process. That will compile for the relevant architecture.

If your delay is indeed due to JITting, this should solve it. Profile your application to be sure.




回答3:


My first solution was to manually create dummy instances of classes and then call the methods with an optional dummy bool variable which would be false by default. This worked but required adding this dummy to every method which is crude and time consuming.

Lucas Trzesniewski's answer is far more through as it prepares all classes and all methods in the code and it does not require any changes to any of my code so it is much easier to implement. The only cost is that by being so thorough it takes longer to complete at about .5 to 1.5 seconds or maybe .5 to 1 second longer than my selective start-up. More than worth it in my case to ensure no delays happen in code.

There was no noticeable spike in memory or CPU usage other than the initial start-up, and memory usage actually slightly decreased, possibly because all code is now complied and optimized.



来源:https://stackoverflow.com/questions/25289484/net-release-code-very-slow-when-running-a-method-for-the-first-time-how-to-fix

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!