我正在尝试追踪当我强调我的C#代码并在低内存条件下运行时发生的崩溃。但是,在某些情况下,我的程序将崩溃并退出,而不是获取OutOfMemoryException。这通常是由于超出缓冲区或堆栈溢出(或损坏)导致的内存损坏造成的。
那么,有没有办法对堆的完整性进行检查,或者有没有办法检查线程上剩余多少堆栈?
出于速度原因,我使用了大量不安全的代码,因此我很可能会在某处破坏内存。不幸的是,崩溃发生后会随机发生。我知道C#会在检测到缓冲区溢出时关闭应用程序,但有没有办法强制它进行检查?
感谢。
答案 0 :(得分:3)
您可以使用Constrained Execution Regions:
来处理这些情况约束执行区域(CER)是用于创建可靠托管代码的机制的一部分。 CER定义了一个区域,在该区域中,公共语言运行时(CLR)被限制为抛出带外异常,这些异常会阻止区域中的代码完全执行。在该区域内,用户代码被限制执行将导致带外异常抛出的代码。
PrepareConstrainedRegions
方法必须紧接try
块之前,并将catch
,finally
和fault
块标记为受约束的执行区域。一旦被标记为约束区域,代码必须仅调用具有强可靠性契约的其他代码,并且除非代码准备好处理失败,否则代码不应分配或对未准备或不可靠的方法进行虚拟调用。 CLR延迟了在CER中执行的代码的线程中止。
当然,CERs非常严格。你不能做太多。它们专为关键的小部分代码而设计。
答案 1 :(得分:2)
在尝试追踪我的问题时,我发现这些文章非常有帮助:
Getting the most out of .NET by taking control
上一篇文章说:
如果无法分配内存 异常对象,运行时将 终止而不给予例外 处理者有机会执行,这 很少会成为理想的行为。 [所以,]而不是简单地拒绝 分配任何进一步的记忆,更温和 更有效的技术是 允许小内存增加 异常对象可以成功 已创建,以及OutOfMemory异常 可以优雅地抛出和处理 托管代码。
我相信这是我需要做的,以避免我的问题。因为我的应用程序内存密集,我不能让它将内存丢弃到页面文件,因为这非常非常慢。我需要我的应用程序将自己限制在物理内存以保持性能可接受。但是当内存耗尽时,我需要引发内存不足异常。我不能让应用程序崩溃!
所以,我将实现该文章中提到的技术,看看是否能解决我的问题。不幸的是,它有点复杂,所以尝试它并不是一件容易的事。
答案 2 :(得分:1)
在某些情况下,操作系统别无选择,只能消除这一过程。为了在进程中引发堆栈溢出或段错误之类的异常,内核必须在错误堆栈上写入EXCEPTION_RECORD,然后才能将控制权交还给进程。如果没有空间写这个记录,那么这个过程就会消失,你无法做任何事情来阻止它。我知道这种情况的两种情况是,如果你在EXCEPTION_STACK_OVERFLOW之后继续增加堆栈,或者如果无法提交保留的堆栈页面,这两种情况都非常罕见。
你最好的办法是修复腐败。尝试在gflags PageHeap保护下运行。如果您知道发生异常的位置,请尝试在调试器下的缓冲区上设置break-on-write断点。或者尝试从写入模式(例如可以是字符串)或从内存中搜索引用返回缓冲区来识别scribbler post-mortem。