Подтвердить что ты не робот

Что происходит между Application.Run и Form.Load?

У меня есть приложение WinForms, написанное на VB.NET для Framework 4.5. Я заметил, что время запуска приложения необычно долго (другие приложения, которые я написал, которые запускают еще большую работу при запуске, запускаются почти мгновенно, для этого приложения требуется > 5 секунд). Время запуска не меняется после нескольких запусков, поэтому я думаю это не относится к нераскрытому CLR-коду во время первого запуска приложения.

Я провел некоторое тестирование, записывая время во время запуска:

Module modMain
    Public MyLog As System.Text.StringBuilder

    <STAThread>
    Public Sub Main()
        MyLog = New System.Text.StringBuilder

        Application.EnableVisualStyles()
        Application.SetCompatibleTextRenderingDefault(False)
        MyLog.AppendLine("Before run: " & Date.Now.ToString & "," & Date.Now.Millisecond.ToString)
        Application.Run(frmMain)
    End Sub
End Module

Sub Main() - точка входа приложений. Он работает frmMain, и там первая реальная вещь, которую я контролирую, - это Sub InitializeComponent(), сгенерированный конструктором:

<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
    MyLog.AppendLine("Init Start: " & Date.Now.ToString & "," & Date.Now.Millisecond.ToString)
    'All the control initializations
    MyLog.AppendLine("Init End: " & Date.Now.ToString & "," & Date.Now.Millisecond.ToString)
End Sub

И, наконец, я прихожу к событию Form.Load

Private Sub frmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    MyLog.AppendLine("Form_Load Start: " & Date.Now.ToString & "," & Date.Now.Millisecond.ToString)
    '...
    MyLog.AppendLine("Form_Load End: " & Date.Now.ToString & "," & Date.Now.Millisecond.ToString)
End Sub

Теперь вывод MyLog выглядит следующим образом:

Before run: 15.12.2014 19:56:47,579
Init Start: 15.12.2014 19:56:51,451
Init End: 15.12.2014 19:56:51,521
Form_Load Start: 15.12.2014 19:56:51,544
Form_Load End: 15.12.2014 19:56:51,547

Вы можете видеть, что основная пауза происходит между Application.Run() и Sub InitializeComponent(). Я знаю из других вопросов, что в потоке графического интерфейса запускается цикл сообщений, но я не знаю, почему для этого приложения он должен быть намного медленнее, чем для других приложений.

Итак, мой вопрос: что именно происходит между Application.Run и точкой, я возвращаю контроль над своим кодом, и могу ли я что-то сделать, чтобы ускорить его? Проделана ли какая-либо работа, связанная с компонентами в форме?

Я уже пробовал использовать frmMain.ShowDialog() вместо Application.Run(frmMain), но это привело к тем же результатам. Я использую Visual Studio Express, поэтому, к сожалению, я не могу использовать более глубокий профилировщик производительности.

Отметьте это как С# и VB.NET, потому что ответы на обоих языках очень приветствуются.

ИЗМЕНИТЬ
Я провел еще несколько тестов, в том числе предлагаемое решение в ответ SLaks. Использование NGEN для прекомпиляции сборки не показало какого-либо заметного эффекта. Поэтому я думаю, что это не компиляция JIT кода InitializeComponent.

Однако я заметил, что в других системах программа запускалась практически мгновенно ( > в 10 раз быстрее), даже если рассматриваемый компьютер был медленнее во всех отношениях. Разница между компьютерами была операционной системой:

Windows 7: Slow start
Windows 8.1: Fast start
Windows Server 2008: Fast start

Это всего лишь дополнительные подсказки, я действительно не знаю, полезно ли это для ответа.

РЕДАКТИРОВАТЬ 2
Глядя на ProcMon во время запуска, я обнаружил, что выполнение зависает в следующих строках:

"15:56:29.3547260","Electrochemical Calculator.exe","5972","CreateFile","C:\Users\Jens\Desktop\Electrochemical Calculator Barebone\Electrochemical Calculator\bin\Release\de\Electrochemical Calculator.resources.dll","PATH NOT FOUND","Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a"
"15:56:29.3548019","Electrochemical Calculator.exe","5972","CreateFile","C:\Users\Jens\Desktop\Electrochemical Calculator Barebone\Electrochemical Calculator\bin\Release\de\Electrochemical Calculator.resources\Electrochemical Calculator.resources.dll","PATH NOT FOUND","Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a"
"15:56:29.3548612","Electrochemical Calculator.exe","5972","CreateFile","C:\Users\Jens\Desktop\Electrochemical Calculator Barebone\Electrochemical Calculator\bin\Release\de\Electrochemical Calculator.resources.exe","PATH NOT FOUND","Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a"
"15:56:29.3549519","Electrochemical Calculator.exe","5972","CreateFile","C:\Users\Jens\Desktop\Electrochemical Calculator Barebone\Electrochemical Calculator\bin\Release\de\Electrochemical Calculator.resources\Electrochemical Calculator.resources.exe","PATH NOT FOUND","Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a"
"15:56:32.8796760","Electrochemical Calculator.exe","5972","CreateFile","C:\Windows\Fonts\StaticCache.dat","SUCCESS","Desired Access: Generic Read, Disposition: Open, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: n/a, ShareMode: Read, Delete, AllocationSize: n/a, OpenResult: Opened"
"15:56:32.8797088","Electrochemical Calculator.exe","5972","QueryStandardInformationFile","C:\Windows\Fonts\StaticCache.dat","SUCCESS","AllocationSize: 9,633,792, EndOfFile: 9,633,792, NumberOfLinks: 1, DeletePending: False, Directory: False"
"15:56:32.8797218","Electrochemical Calculator.exe","5972","ReadFile","C:\Windows\Fonts\StaticCache.dat","SUCCESS","Offset: 0, Length: 60, Priority: Normal"
"15:56:32.8797429","Electrochemical Calculator.exe","5972","CreateFileMapping","C:\Windows\Fonts\StaticCache.dat","FILE LOCKED WITH ONLY READERS","SyncType: SyncTypeCreateSection, PageProtection: "

Проблема возникает только при создании Release и только при запуске программы непосредственно из проводника Windows. Сборка отладки запускается мгновенно (0,3 секунды, по сравнению с 5-10 секундами), так же как и сборка Release при запуске из Visual Studio.

4b9b3361

Ответ 1

Ну, вы устранили все нормальные источники задержек запуска. Это определенно не имеет никакого отношения к Application.Run(), который не запускается до тех пор, пока форма метода InitializeComponent() не закончится. И вы исключили накладные расходы, используя Ngen.exe. Не забудьте различать холодные и теплые задержки запуска, если он будет только медленным при первом запуске программы, тогда это проблема аппаратного обеспечения, вам нужен более быстрый диск. Тот факт, что на некоторых машинах он только медленный, указывает на экологическую проблему.

Запущен кодом, который запускается в InitializeComponent(). Другими словами, все конструкторы и средства настройки элементов управления в вашей форме. Это обычно занимает очень мало времени, но, безусловно, есть проблемы. Вам нужно искать нетривиальный элемент управления, особенно тот, который использует COM (aka ActiveX) под капотом. Как и WebBrowser. Есть еще много возможностей, все, чье имя класса начинается с "Топора". Такие элементы управления могут загружать множество других DLL и могут быть интересны программному обеспечению безопасности.

Некоторые советы по отладке:

  • Убедитесь, что у вас есть хорошая резервная копия и вы можете удалить элементы управления из формы, начиная с нетривиальных.
  • Задержка в 5 секунд достаточно длинна, чтобы заметить одноэтапный метод InitializeComponent(). Мгновенно сообщает вам, какой конкретный элемент управления и оператор вызывает задержку.
  • Переключение отладчика в неуправляемый режим говорит вам намного больше о том, какие другие библиотеки DLL загружаются в вашу программу. Project + Properties, Debug, отметьте опцию "Включить отладку собственного кода". Следите за окном вывода во время отладки, вы увидите уведомления о загрузке для любой загруженной неуправляемой DLL. Это может указывать на конкретную DLL, которая вызывает задержку.
  • Если возможно, отключите антивирусную программу, чтобы устранить задержки из-за неправильного сканирования DLL.
  • утилита SysInternals TcpView является отличным средством для обнаружения сетевых задержек. Будьте осторожны, когда вы видите, что ваша программа связывается с сервером CRL, запросы списка отзыва сертификатов могут быть медленными.
  • Сервисная программа SysInternals" Process Monitor отлично подходит для заметок из-за большинства других вещей. Трассировка может быть очень большой, сохранить ее и опубликовать на сайте совместного доступа к файлам, если вам нужен другой набор глаз.

Ответ 2

Это время затрачено на загрузку каждой сборки, используемой элементами управления формы, и JIT-метод InitializeComponent.

Ответ 3

Как сказал Ханс, вы уже устранили очевидное, и для меня проблема кажется экологической... так как вы устраняете эту проблему в экстремальных условиях...

Поскольку процесс последовательно занимает 5 и более секунд (при запуске из проводника), вот некоторые из подходов, которые я мог бы принять в этой ситуации -

Примечание. Поскольку существует вероятность возникновения проблемы, вам, возможно, придется несколько раз повторить эксперимент, чтобы получить достойные результаты. Мне, очевидно, все еще сложно гарантировать результаты... Если бы я лично это делал, я бы надеялся импровизировать, если эти идеи высокого уровня не работают на 100%. Но я бы, безусловно, дал им шанс.

  • Используйте Procdump, чтобы запустить процесс, и выгрузите n полные дампы после Elapsed Time счетчик производительности для процессов достигает некоторого значения (например, 2 или 3 или 4). Затем вы можете открыть эти дампы в windbg (большинство информации, сложно использовать) или VS.Net(проще в использовании, но может или не показывать то, что вы хотите найти, даже если оно есть). Используйте отладку смешанного режима, когда открытие дампа).

  • На аналогичных строках, но менее мощный, более сложный, чтобы получить право. Настройте ProcessExplorer, чтобы показать собственные следы стека, когда вы смотрите в свойствах процесса... Как только вы запустите процесс, переключитесь на ProcessExplorer и посмотрите на трассировки стека для различных потоков в процессе. Это сложнее, потому что в зависимости от количества потоков есть, вручную просматривая их трассировки стека могут вообще не работать вообще. Возможно, стоит сделать один или два выстрела, если это сделает проблему очевидной с минимальными усилиями.

В любом случае убедитесь, что ваши символы настроены на серверы общедоступных символов Microsoft. Чтобы вы получали большую часть информации из собственных трассировок стека.

Подводя итог, идея состоит в том, что в этом случае функция высокого уровня должна иметь высокую вероятность отображения в трассировке стека, если все, что находится ниже, занимает несколько секунд.

Примечание. Как только вы знаете функцию высокого уровня, это может быть конец истории, или может быть необходимо связать ее с другими процессами на системном уровне.. (снова анти -вирус - типичный пример). Но вы наверняка можете ожидать, что у вас будет больше подсказок, чтобы помочь подкрепить любую такую ​​гипотезу.