Sea*_*n U 5 .net c# stack-overflow multithreading
我遇到过一种情况,根据minidump,某些文件在递归下降解析器中导致堆栈溢出.不幸的是我不能让我的手,这是否为了重现该问题(客户有保密性问题),这让我有点砍断诊断上真正的问题一时还文件的例子.
很明显,解析器需要一些关注,但现在我的首要任务是保持程序运行.作为权宜之计,我该怎样做才能阻止整个计划的落实?
我的第一选择是找到某种方法来预测我在堆栈上的空间不足以便我可以在溢出发生之前优雅地中止解析器.无法解析文件是可以接受的选项.第二种选择是让它发生,捕获错误并记录它,然后继续其余的数据.
解析发生在Parallel.ForEach()循环中.如果有帮助,我愿意将其换成其他方法.
编辑: 如果我能够获得当前线程堆栈的大小以及堆栈指针的位置,那么真正的杀手是什么.这可能吗?
编辑2: 我终于设法从某人那里取出一个样本文件并将错误记录在调试器中.事实证明,它根本不属于我们的代码 - HtmlAgilityPack中的某个地方发生了异常.所以看起来我将不得不尝试找到一个完全不同的方法.
默认情况下,桌面 CLR 上的堆栈有 1 MB 限制,但您可以增加它。
您可以使用连续传递样式来使用堆而不是堆栈。
在 C# 5.0 中,编译器提供了异步机制,可以自动执行此过程。我还没有在最新版本中尝试过这个。正如 Alex 所提到的,C# 中不支持尾部调用优化,这可能是采用 F# 来解决解析问题的充分理由。以下是有关使用 F# 进行词法分析和解析的一些材料。YMMV,如本文 所示。
您还需要图形循环检测,以使您的程序在存在错误输入的情况下保持稳定。
作为收集更多信息的一种方法,您可以通过累加器整数来跟踪调用堆栈的深度。这不会直接转化为所述调用堆栈消耗的内存,但它为您提供了一个总体思路。例如,当该数字大于某个用户可配置或预定义的阈值时,您可以抛出并捕获自己的异常。
public void Recursive(int acc)
{
if (acc > myLimit)
throw new MyOverflowException(acc);
Recursive(acc+1);
}
Run Code Online (Sandbox Code Playgroud)
然后在调用站点:
try { Recursive(0); } catch (MyOverflowException) { /* handle it*/ }
Run Code Online (Sandbox Code Playgroud)
根据要求,我将把您链接到 Eric Lippert 撰写的关于这个主题的精彩博客。
| 归档时间: |
|
| 查看次数: |
322 次 |
| 最近记录: |