.NET 中的堆栈溢出导致 IIS 的 CPU 使用率达到 100% - 为什么没有 StackOverflowException?
我在 Server 2008 R2 + IIS 7.5 上运行的 ASP.NET 应用程序中有一些代码。每当我加载特定页面时,它就会永远挂起并使 IIS 的 CPU 使用率达到 100%。我最终找到了问题所在。
public string Comments
{
get { return this.Comments; }
}
糟糕 - 应该返回 this.Photo.Comments
。所以,我的问题是,为什么 .NET 没有生成 StackOverflowException,而是让 IIS 以 100% CPU 运行的时间远远超过其应有的时间。根据我使用 .NET 编程的经验,执行上述操作时,需要几秒钟或更短的时间才能获得 StackOverflowException。那么它怎么可能还在IIS上运行了近30分钟呢?
I had some code in an ASP.NET application running on Server 2008 R2 + IIS 7.5. Whenever I loaded a particular page, it would hang forever and send IIS to 100% CPU usage. I eventually tracked down the problem.
public string Comments
{
get { return this.Comments; }
}
Oops - should have been return this.Photo.Comments
. So, my question is, why didn't .NET generate a StackOverflowException, but instead let IIS run at 100% CPU for far longer than it should have taken. In my experience programming with .NET, it takes seconds or less to get a StackOverflowException when doing something like the above. So how could it still be running for almost 30 minutes on IIS?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
JIT 编译器可能优化了对
YourClass::get_Comments()
的方法调用(这就是 IL 的样子),并使用jmp
内联代码(或者无论 x86 汇编器是什么)循环构造,因为没有任何值被传递。只是一个想法。这篇老文章值得一看:
原样:
我还使用一个简单的控制台应用程序重现了这一点:
在关闭优化的调试模式下,我抛出了堆栈溢出异常。打开 Jit 优化并编译发布版本后,应用程序将永远运行。这表明可能发生了内联循环。
C#2.0、3.0 和 4.0 似乎也是这种情况。
It's possible the JIT compiler optimised out a method call to
YourClass::get_Comments()
(which is what the IL would look like) and inlined the code with ajmp
(or whatever the x86 assembler would be) loop construct because there weren't any values being passed around. Just a thought.This old article is worth a look:
As is:
I also reproduced this with a simple console application:
In debug mode with optimisations turned off I get a stack overflow exception thrown. Upon turning on Jit Optimisations and compiling a release build the app just runs forever. This suggests that inlining to a loop has probably happened.
This also appears to be the case with C#2.0, 3.0 and 4.0.
我尝试将此代码放入类库中并通过单元测试运行它。
它会导致 MS 测试代理因堆栈溢出异常而崩溃。
可能发生的情况是您遇到了 stackoverflow 异常。这会导致应用程序池崩溃。然后 IIS 提取应用程序池的新副本,它再次崩溃......
检查事件日志记录以了解应用程序池回收/停止。
I tried putting this code into a class library and running it with a unit test.
It crashes the MS test agent with a stack overflow exception.
What may be happening is that you are getting a stackoverflow exception. This is crashing the application pool. IIS then pulls up a new copy of the app pool, and it gets crashed again ....
Check your event logging for application pool recycling / stops.
这种情况在开发和发布中都会发生吗?
抱歉,我不确定,但这是我的猜测。您在某处配置了自动重试。因此操作过程因 StackOverflowException 失败。 IIS 不会让用户收到消息,而是会使用新进程重试。这种情况一直持续下去。所以重复的重试会耗尽所有的CPU。
我已经搜索并试图找到一个可能解释它的自动重试机制,但到目前为止还没有运气,但您会更多地了解您的配置。
您可以尝试的另一个检查是编写一些分配大量内存的内容,并查看 OutOfMemoryException 是否会发生同样的情况。如果是这样,几乎可以肯定是自动重试。
Does this happen in development as well as release?
I'm sorry I don't know for sure, but here is my speculation. Somewhere you have an Auto-retry configured. So the operation process fails from a StackOverflowException. Rather than the user getting a message, IIS retries with a new process. This goes on and on and on. And so the repeated retries eat all the CPU.
I've searched to try and find an auto-retry mechanism that might account for it, but had no luck so far, but you will know more about your configuration.
Another check you could try is write something which allocates a huge amount of memory and see if the same thing happens with OutOfMemoryException. If it does, it is almost certainly an auto-retry.