.NET 中的堆栈溢出导致 IIS 的 CPU 使用率达到 100% - 为什么没有 StackOverflowException?

发布于 2024-11-05 23:45:16 字数 419 浏览 0 评论 0原文

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

扎心 2024-11-12 23:45:16

JIT 编译器可能优化了对 YourClass::get_Comments() 的方法调用(这就是 IL 的样子),并使用 jmp 内联代码(或者无论 x86 汇编器是什么)循环构造,因为没有任何值被传递。只是一个想法。

这篇老文章值得一看:

Jit 优化:内联 (II)

“一个真正优秀的典型例子
内联候选者是一个属性
获取器/设置器。这些通常是
非常小的方法,通常只是
进行内存获取或存储,所以它是
通常尺寸和速度优于内联
他们。”

原样:

编写高性能托管应用程序:入门 - 托管代码和CLR JIT

我还使用一个简单的控制台应用程序重现了这一点:

class Program
{
  static void Main(string[] args)
  {
    MyClass mc = new MyClass();
    string s = mc.Comments;
  }
}

public class MyClass
{
  public string  Comments
  {
    get { return this.Comments; }
  }
}

在关闭优化的调试模式下,我抛出了堆栈溢出异常。打开 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 a jmp (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:

Jit Optimizations: Inlining (II)

"A typical example of a really good
candidate for inlining is a property
getter/setter. These are usually
really small methods that usually just
do a memory fetch or store, so it's
usually a size and speed win to inline
them."

As is:

Writing High-Performance Managed Applications : A Primer - Managed Code and the CLR JIT

I also reproduced this with a simple console application:

class Program
{
  static void Main(string[] args)
  {
    MyClass mc = new MyClass();
    string s = mc.Comments;
  }
}

public class MyClass
{
  public string  Comments
  {
    get { return this.Comments; }
  }
}

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.

倾其所爱 2024-11-12 23:45:16

我尝试将此代码放入类库中并通过单元测试运行它。

它会导致 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.

你曾走过我的故事 2024-11-12 23:45:16

这种情况在开发和发布中都会发生吗?

抱歉,我不确定,但这是我的猜测。您在某处配置了自动重试。因此操作过程因 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文