2016-01-27 2 views
6

У меня есть приложение asp.net, которое рушится. Существует запись для этого в журналах событий Windows, который содержит этот стек вызовов:Нормально ли видеть интерфейс в clr callstack?

Exception type: EntryPointNotFoundException 
    Exception message: Entry point was not found. 
    at ***.Interfaces.Portal.Repository.ILookup.get_LookupDataCollection() 
    at ***.Portal.Repository.Lookup.GetLookUpValue(ILookup lookup, Int32 index) 
    at ***.Portal.Repository.Lookup.GetLookUpValue(ILookup lookup) 
    at ***.HttpModules.RuntimeHttpModule.SetPageUrlInfoInContext(PageUrlInfo pinfo) 
    at ***PortalRuntime.HttpModules.RuntimeHttpModule.BeginRequest(Object sender, EventArgs e) 
    at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 
    at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) 

Это происходит только на машине клиента, и я не был в состоянии воспроизвести его на месте. Как вы видите сверху, есть интерфейс (ILookup, который действительно является интерфейсом, а не классом).

Я построил аналогичный образец (метод, называемый через интерфейс). Visual Studio 2015 достаточно умен, чтобы показать это:

ConsoleApplication2.exe!ConsoleApplication2.Lookup.GetLookupId(ConsoleApplication2.ILookup lookup) Line 37 C# 

Но там вы все еще видите класс, который реализует метод. Я также привязался к своему образцу с помощью windbg и печатал стек, когда приложение сидит в точке останова в методе, который вызывается через интерфейс: интерфейс не был в стеке.

Вот мой вопрос:

  • Это нормально, чтобы увидеть интерфейс в CLr стеке вызовов (особенно без класса, который реализует его)? Кажется, я никогда раньше не видел такого коллажа ... Кто-нибудь еще? (Я имею в виду это вообще, независимо от второй части моего вопроса)

  • Here - очень похожий вопрос: @Hans Passant в своем первом комментарии говорит «неспособность решить метод реализации для метода интерфейса» и OP говорит, что «вы уже ответили на мой вопрос своим первым комментарием». Так это действительно первопричина? Кто-нибудь знает об исправлении для этого? Или это просто специальная версия CLR?

ответ

7

Я могу объяснить, почему вы видите это немного, это не поможет вообще решить вашу проблему. Я также не знаю достаточно о том, как CLR связывает методы интерфейса с их реализацией, он безумно микрооптимизирован.

Проблема заключается в том, что джиттер должен генерировать код для метода, который содержит вызов метода интерфейса. Но он еще не может знать идентичность ссылки на объект. Это не известно на 100% точно до тех пор, пока код не выполнится. Итак, что это такое, выделите заглушку, держатель места для целевого метода. И генерирует инструкцию CALL для этого заглушки. Фактическое имя этого метода заглушки не имеет значения, оно снова исчезнет, ​​когда будет решен реальный целевой метод.

Сам заглушка генерирует вызов в CLR для разрешения целевого метода, теперь зная истинную идентификацию ссылки на объект и, следовательно, какой конкретный метод реализации необходимо выполнить. И исправляет машинный код, поэтому адрес CALL заменяется. Таким образом, next время, в течение которого выполняется метод, вы не платите цену за привязку метода, а вызов выполняется с максимальной возможной скоростью деформации.

Как уже отмечалось, название заглушки не имеет значения, поскольку оно является временным. Дать ему имя метода интерфейса очень полезно для диагностики исключения MissingMethodException. Хорошая идея.

Настоящая проблема заключается в том, что сборка, которая была загружена, не та, с которой вы создали свой код. Вероятно, старый, который вы забыли перераспределить. Или вы просто забыли перестроить его, когда вы изменили интерфейс, потому что он не является частью решения. Таким образом, у него нет реализации метода интерфейса, CLR обнаруживает это очень поздно, когда выполняется заглушка.Таким образом, вы видите имя метода заглушки в стеке вызовов.

+0

Большое спасибо за объяснение! Это дает понять, почему мы видим интерфейс в верхней части стека. Может быть, один комментарий: «И исправляет машинный код, поэтому адрес CALL заменяется. Поэтому в следующий раз, когда метод выполняется, вы не платите цену за привязку метода «Да, но что, если в следующий раз метод вызывается с другим типом, который реализует интерфейс? Код jitted не может иметь фиксированный вызов для одной реализации. Но в любом случае, я понимаю вашу точку зрения. Еще раз спасибо! – gregkalapos

+0

Да, это та часть, о которой я не знаю. Оно работает. –