Случай ужасного снижения производительности 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

Как заставить Activator.CreateInstance работать примерно в 20 раз медленнее с совершенно пустым типом

Ответы на вопрос(0)

Ваш ответ на вопрос