Cha*_*ion 59 .net c# stack-overflow
我知道无法捕获.NET中的StackOverflowExceptions,删除它们的进程,并且没有堆栈跟踪.这在MSDN上正式记录.但是,我想知道这种行为背后的技术(或其他)原因是什么.所有MSDN都说:
在.NET Framework的早期版本中,您的应用程序可以捕获StackOverflowException对象(例如,从无限递归中恢复).但是,目前不鼓励这种做法,因为需要大量额外的代码来可靠地捕获堆栈溢出异常并继续执行程序.
什么是"重要的附加代码"?这种行为还有其他记录的原因吗?即使我们无法捕获SOE,为什么我们至少不能获得堆栈跟踪?几个同事和我只是沉没几个小时来调试生产StackOverflowException,这可能需要几分钟的堆栈跟踪,所以我想知道我是否有充分的理由让我受苦.
Han*_*ant 85
线程的堆栈由Windows创建.它使用所谓的保护页来检测堆栈溢出.此MSDN Library文章中描述的用户模式代码通常可用的功能.基本思想是保留堆栈的最后两页(2 x 4096 = 8192字节),并且对它们的任何处理器访问都会触发页面错误,该页面错误变为SEH异常STATUS_GUARD_PAGE_VIOLATION.
在属于线程堆栈的那些页面的情况下,内核拦截这一点.它改变了这两个页面中第一个页面的保护属性,从而为线程提供了一些紧急堆栈空间来处理事故,然后重新引发STATUS_STACK_OVERFLOW异常.
此异常又由CLR拦截.那时剩下大约3千字节的堆栈空间.例如,这不足以运行即时编译器(JITter)来编译可以处理程序中的异常的代码,JITter需要更多的空间.因此,CLR无法做任何其他事情,只能粗暴地中止该线程.并且通过.NET 2.0策略也终止了该过程.
注意这在Java中是不是一个问题,它有一个字节码解释器,因此可以保证可执行的用户代码可以运行.或者在用C,C++或Delphi等语言编写的非托管程序中,代码在构建时生成.然而,这仍然是一个非常难以处理的事故,堆栈中的紧急空间被烧毁,因此没有任何情况继续在线程上运行代码是安全的.程序可以继续正常运行,并且线程在完全随机的位置中断并且相当损坏的状态是不太可能的.
如果在考虑在另一个线程上提出事件或者删除winapi中的限制(保护页面的数量不可配置)时有任何努力,那么这是一个非常保密的秘密或者只是被认为没有用处.我怀疑后者,不知道这个事实.
Typ*_*eIA 16
堆栈几乎存储了程序状态的所有内容.调用方法时每个返回站点的地址,局部变量,方法参数等.如果一个方法溢出堆栈,它的执行必须立即停止(因为没有剩余的堆栈空间继续运行) .然后,为了优雅地恢复,有人需要清理该方法在堆栈死亡之前所做的任何操作.这意味着在调用方法之前知道堆栈的样子.这会产生一些开销.
如果你无法清理堆栈,那么你也无法获得堆栈跟踪,因为生成跟踪所需的信息来自"展开"堆栈以发现调用哪些方法.
要正常处理堆栈溢出或内存不足的情况,有必要在堆栈实际溢出或堆内存完全耗尽之前触发异常,此时可用堆栈和堆资源足以执行任何在捕获异常之前需要运行的清理代码.在堆栈溢出异常的情况下,干净地处理它们基本上需要在每个方法的入口处检查堆栈指针(实际上不应该那么昂贵).通常情况下,它们是通过在堆栈末尾设置访问违规陷阱来处理的,但这样做的问题是陷阱不会触发,直到已经太晚才能干净地处理事情.可以将陷阱设置为在堆栈的最后一个内存块上触发,而不是在过去的一个内存块上启动,并且一旦它触发并触发a StackOverflowException,系统就会将陷阱更改为通过堆栈的块,但问题是没有一旦堆栈解开那么远,确保"几乎堆栈外"陷阱重新启用的好方法.
话虽如此,另一种方法是允许线程为线程吹掉堆栈时应该发生的事情设置一个委托,然后说如果StackOverflowException线程的堆栈被清除,它将运行提供的委托.可以在运行委托之前重新设置陷阱(堆栈在该点处为空),并且代码可以维护一个线程状态对象,委托可以使用该对象来知道是否finally跳过了任何重要的块.
| 归档时间: |
|
| 查看次数: |
2517 次 |
| 最近记录: |