动态语言运行时与IIS 7.5的组合存在Bug问题

4

很抱歉这个问题比较长,但我觉得你们会发现它很有价值。在我开始之前,让我说一句,我确实尝试创建一个独立的控制台应用程序,但遗憾的是证明了不可能。这个 bug 在控制台应用程序中不会发生。在一个自包含的 ASP.NET 应用程序中也不会发生。它只会在运行在 Windows 7 上的 IIS 7.5 中发生。

错误似乎与动态语言运行时有关,因为它涉及到 __TransparentProxy(通过 WCF)和 dynamic 变量(一个 int 的变量)的组合。产生问题的那一行是对静态方法的调用(该方法恰好不包含方法体),传入代理和动态 int。

一旦方法被调用,w3wp.exe 进程就会占用整个 CPU,并开始非常快地增加内存(对我来说大约每秒增加 100 兆字节,尽管由于垃圾回收而逐渐减少)。

为了重现此错误,请在 Visual Studio 中创建一个新的 ASP.NET 网站(“新建”|“项目”|“C#”|“Web”|“ASP.NET Web 应用程序”)。然后在 IIS 中创建一个新站点,其主目录是您的新项目(还要给“Everyone”分配完全读写权限,并确保应用程序池使用 .NET 4.0)。为新站点指定一个特定的端口,比如 7080。最后,将此代码粘贴到 Global.asax.cs 文件中:

public class Global : System.Web.HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        dynamic dynamicId = 5;

        var serviceUrl = "http://localhost:7182/FooServices.svc";
        ChannelFactory factory = new ChannelFactory<IFooServices>(new WSHttpBinding(), new EndpointAddress(serviceUrl));
        factory.Open();
        IFooServices fooServices = ((ChannelFactory<IFooServices>)factory).CreateChannel();

        BlowUpTheProgram(fooServices, dynamicId);  // This line hangs
    }

    [ServiceContract]
    public interface IFooServices
    {
        [OperationContract]
        void Bar();
    }

    public static void BlowUpTheProgram(IFooServices eventServices, int authorMailboxId)
    {
    }
}

现在在浏览器中访问该网站,使用http://localhost:7080(或您选择的端口)进行访问。准备好任务管理器,因为您需要在确认了报告的症状后终止w3wp.exe进程。
为了确认代理和动态是否协同工作以显示此错误,请更改此行:
dynamic dynamicId = 5;

致:

int dynamicId = 5;

重试一下,您会发现问题已经消失了并且页面已经能够加载。现在将其改回 dynamic 然后更改这一行:

IFooServices fooServices = ((ChannelFactory<IFooServices>)factory).CreateChannel();

致:

IFooServices fooServices = null;

重试一次,你会发现在这种情况下问题也已经消失了。

最后,如果我附加调试器并断点,我可以看到它在卡在这个方法调用时正在做什么。似乎总是显示如下:

mscorlib.dll!System.RuntimeMethodHandle.GetDeclaringType(System.IRuntimeMethodInfo method) + 0x2f 字节
mscorlib.dll!System.Reflection.Emit.DynamicResolver.ParentToken(int token) + 0x1f3 字节
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.Reflection.Emit.DynamicMethod.CreateDelegate(System.Type delegateType, object target) + 0x29 字节
System.Core.dll!System.Linq.Expressions.Expression>.Compile() + 0xbb 字节
System.Core.dll!System.Runtime.CompilerServices.CallSiteBinder.BindCore>(System.Runtime.CompilerServices.CallSite> site, object[] args) + 0x10a 字节
System.Core.dll!System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid3(System.Runtime.CompilerServices.CallSite site = {System.Runtime.CompilerServices.CallSite>}, WebApplication1.Global arg0 = {ASP.global_asax}, WebApplication1.Global.IFooServices arg1 = {System.Runtime.Remoting.Proxies.__TransparentProxy}, object arg2 = 5) + 0x3f0 字节
WebApplication1.dll!WebApplication1.Global.Application_Start(object sender = {System.Web.HttpApplicationFactory}, System.EventArgs e = {System.EventArgs}) Line 19 + 0x1b8 字节 C#

值得一提的是,我尝试在三台不同的机器上进行此操作,只能在 Windows7/IIS7.5 上复现此问题。 在 Windows Server 2008 / IIS7 上没有问题。

问题是,如何解决这个问题并成功调用该方法? 还有,为什么会发生这种情况? 我不希望在调用使用 DLR 的事物时过于小心,因为它会使 IIS 崩溃。


@Jamie,我正在使用Dapper Dot Net。返回类型是动态的。但你说得很对——我想我可以绕过它并强制在此调用中不使用DLR。尽管如此,我仍然想知道为什么会发生这种情况。 - Kirk Woll
1
我自己也遇到了一些动态问题。在将结果传递给方法时进行类型转换可能会为您解决问题。DontBlowUpTheProgram(fooServices, (int)dynamicId); - Jamie Dixon
请查看我的问题,了解有关该问题的一些信息:https://dev59.com/K2HVa4cB1Zd3GeqPq-DW。虽然它与你的问题不完全相关,但谁知道,在某些方面可能会有关联。这就引发了这个问题:https://dev59.com/-Wkw5IYBdhLWcg3whK08。 - Jamie Dixon
我在 stackoverflow 上发现了一个类似的问题,并且我已经能够在控制台应用程序和 Windows 窗体应用程序中重现相同的问题。 - lstern
我为这个问题的长度道歉,但是不要抱歉。你在尝试解决问题时提供的详细信息和清晰度非常有价值,可以帮助我们得出准确的答案。 - Bernhard Hofmann
显示剩余3条评论
1个回答

6

我无法解释这种情况发生的原因,但是将您的 dynamic 对象转换为 int 并在传递参数时使用会起作用。

DontBlowUpTheProgram(fooServices, (int)dynamicId); 

也许对内部结构了解更多的人会提供更详细的解释。

如果你无法回答问题,为什么要提交答案?这样的事情应该在评论中讨论,而不是作为答案。我本来期待着一个答案,但看到你的第一行后就感到有些失望了。 - Phil
2
我回答了这个问题。问题是如何解决它,而不是为什么它不起作用。自从第一次发布以来,它已经有所改变,但在这里我回答了如何解决它,而没有解释为什么。 - Jamie Dixon
1
@Phil,我认为Jamie提供了非常有用的答案。坦率地说,如果这个问题没有被赞过,SO会稍微“展示”一下它。(“未回答的问题”)但是,我完全打算给这个答案点赞(最终),而且很可能会将其作为“采纳”的答案。最终,我猜想我会在上面开启悬赏以期获得其他意见和更多关注。但是,Jamie非常有帮助。 - Kirk Woll
1
这解决了我的问题。虽然我不明白细节,但你提供了过去6个小时疑难解答的解决方案,所以我给你一个巨大的加1! - Bernhard Hofmann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接