Случай ужасного снижения производительности Activator.CreateInstance
Интересное поведение мы наблюдаем в нашем приложении на стороне сервера .NET.
Работа с процессором / памятью со временем замедляется. Мы использовали PerfView, чтобы попытаться найти виновника, и кажется, чтоActivator.CreateInstance
единственный.
Как мы нашли это? Мы выполнили ту же работу в начале нового сеанса и после выполнения около 3000 отчетов. В первом случае PerfView даже не показывалActivator.CreateInstance
- его процент был слишком близок к 0% (но будьте уверены, его назвали). Во втором случае он показал 28%.
Итак, с чем же дело?Activator.CreateInstance
Мы используем .NET 4.5
РЕДАКТИРОВАТЬ
Мы используем версию конструкции по умолчанию.Activator.CreateInstance
РЕДАКТИРОВАТЬ 2
Важное событие. Нам удалось сузить дело до использования системы отчетности Microsoft в сочетании с включением.NetFx40_LegacySecurityPolicy
На самом деле, у нас есть небольшой тестовый пример вызоваActivator.CreateInstance
до и после создания крошечного отчета. Пожалуйста, найдите под выводом:
new() = 4, Activator.CreateInstance() = 38
Building one report ... done.
new() = 13, Activator.CreateInstance() = 2261
Что это значит, что это призваниеActivator.CreateInstance()
500 000 раз до создания отчета заняло всего 38 миллисекунд.После крошечного отчета потребовалось в 59 раз больше!
Вот весь код:
Program.cs
using System;
using System.Diagnostics;
using System.IO;
using Microsoft.Reporting.WebForms;
namespace CreateInstanceTest
{
internal class TestClass
{
}
internal class Program
{
public static void Main()
{
const int COUNT = 500000;
long newTime;
long createInstanceTime;
DoOneRound(COUNT, out newTime, out createInstanceTime);
Console.WriteLine("new() = {0}, Activator.CreateInstance() = {1}", newTime, createInstanceTime);
Console.Write("Building one report ... ");
Console.Out.Flush();
RunReport();
Console.WriteLine("done.");
DoOneRound(COUNT, out newTime, out createInstanceTime);
Console.WriteLine("new() = {0}, Activator.CreateInstance() = {1}", newTime, createInstanceTime);
Console.WriteLine("Press any key to terminate ...");
Console.ReadKey();
}
public static void DoOneRound(int count, out long newTime, out long createInstanceTime)
{
var sw = new Stopwatch();
sw.Start();
for (int index = 0; index < count; ++index)
{
// ReSharper disable ObjectCreationAsStatement
new TestClass();
// ReSharper restore ObjectCreationAsStatement
}
sw.Stop();
newTime = sw.ElapsedMilliseconds;
var type = typeof(TestClass);
sw.Restart();
for (int index = 0; index < count; ++index)
{
Activator.CreateInstance(type);
}
sw.Stop();
createInstanceTime = sw.ElapsedMilliseconds;
}
private static void RunReport()
{
var localReport = new LocalReport();
localReport.LoadReportDefinition(new StringReader(
""+
""+
" "+
" 1in"+
" "+
" 1in"+
" "+
" "+
" 1in"+
" "+
" "+
" "+
" "+
" "+
" "+
" =Globals!OverallTotalPages"+
" "+
" "+
" "+
" "+
" "+
" "+
" "+
" "+
""
));
localReport.Render("pdf");
}
}
}
App.config
CreateInstanceTest.csproj
Debug
AnyCPU
{83690315-C8AC-4C52-9CDD-334115F521C0}
Exe
CreateInstanceTest
CreateInstanceTest
v4.5
AnyCPU
true
full
bin\$(Configuration)\
prompt
4
false
false
false
DEBUG;TRACE
true
TRACE
Designer
Обратите внимание, что отключениеNetFx40_LegacySecurityPolicy
в конфиге делает чудеса:
new() = 7, Activator.CreateInstance() = 106
Building one report ... done.
new() = 7, Activator.CreateInstance() = 78
К сожалению, мы застряли сNetFx40_LegacySecurityPolicy
по другим причинам, поэтому отключить его нельзя.
Любой вклад приветствуется.
РЕДАКТИРОВАТЬ 3