我正在开发一个发生StackOverflowException的.Net 2.0应用程序.有没有办法在应用程序中止之前/期间打印/记录堆栈跟踪?这是一个长期运行的服务器端进程,很难在调试器下执行.我知道无法捕获StackOverflowException.
我正在尝试在Haskell中解决算法难题,为此我需要相当大的数据结构.但是问题解决网站我提交了我的解决方案,不使用任何运行时选项来允许更大的堆栈,但我听说我可以使用编译器选项作为pragma.我在我的代码中尝试使用以下编译指示:
{-# OPTIONS_GHC -O2 -rtsopts -with-rtsopts=-K32m #-}
Run Code Online (Sandbox Code Playgroud)
然后我编译ghc --make algo.hs.但是,当我在一些大型测试中运行我的机器时,程序崩溃并发生堆栈溢出,并报告当前堆栈大小为8MB.另一方面,当我编译时:
ghc -rtsopts -with-rtsopts=-K32M --make algo.hs -fforce-recomp
Run Code Online (Sandbox Code Playgroud)
该程序可以在相同的数据上正常工作,而无需添加任何+RTS参数.我使用的是GHC 7.0.2,但解决问题的网站使用的是6.12.3,所以我最好也在寻找可以使用旧版本的解决方案.
为了学习Clojure,我正在4clojure解决问题.我目前正在问题164,在那里你要枚举(部分)DFA接受的语言.一个有趣的条件是语言可能是无限的,因此解决方案必须是懒惰的(在这种情况下,解决方案的测试用例)(take 2000 ....
我有一个可以在我的机器上运行的解决方案,但是当我在网站上提交它时,它会炸掉堆栈(如果我增加可接受的字符串数量,从2000到20000确定,我也在本地吹掉堆栈,所以这是一个我解决方案的不足之处).
我的解决方案[1]是:
(fn [dfa]
(let [start-state (dfa :start)
accept-states (dfa :accepts)
transitions (dfa :transitions)]
(letfn [
(accept-state? [state] (contains? accept-states state))
(follow-transitions-from [state prefix]
(lazy-seq (mapcat
(fn [pair] (enumerate-language (val pair) (str prefix (key pair))))
(transitions state))))
(enumerate-language [state prefix]
(if (accept-state? state)
(cons prefix (follow-transitions-from state prefix))
(follow-transitions-from state prefix)))
]
(enumerate-language start-state ""))
)
)
Run Code Online (Sandbox Code Playgroud)
它接受DFA
'{:states #{q0 q1 q2 q3}
:alphabet #{a b c} …Run Code Online (Sandbox Code Playgroud) 对于C#AI程序,我使用递归调用来查找最佳的下一步(使用30x30阵列来存储当前的板状态).对于我所做的每一个动作,我想看看我可以从新的棋盘状态中做出哪些可能的动作将是最好的...依此类推,直到我达到"游戏结束"的位置(此时无法进一步移动)状态)或计时器停止进程并且不再进行进一步的递归调用(并且返回"最佳"已知位置).这只是为了解释为什么我必须使用递归(它不是尾递归)而且我不能使用单个(全局)电路板状态,但必须从当前状态搜索所有电路板状态.
(有时)我得到一个System.StackOverflowException.有没有办法在下一次递归调用之前检查可用的堆栈空间?然后我可以将当前状态作为"到目前为止找到的最佳位置"返回,而不是进行下一次递归调用.即,当可用堆栈变得太小时,它也应该算作基本情况.
当然,另一个选择可能是将每个递归调用放在try..catch块中并使用它作为基本情况来处理System.StackOverflowException?
文章可以在这里找到.
我正在读取粉碎堆栈并发现自己被卡在example3.c上.
0x80004a3 <main+19>: call 0x8000470 <function>
0x80004a8 <main+24>: addl $0xc,%esp
0x80004ab <main+27>: movl $0x1,0xfffffffc(%ebp)
0x80004b2 <main+34>: movl 0xfffffffc(%ebp),%eax
Run Code Online (Sandbox Code Playgroud)
作者表示我们想要跳过0x80004a8,0x80004b2并且这个跳转是8个字节; 作者如何确定这是8个字节?我重新创建了代码并发送了它objdump,发现它不是8个字节(我在64位机器上,但我确保使用32位编译):
8048452: e8 b5 ff ff ff call 804840c <function>
8048457: c7 44 24 1c 01 00 00 movl $0x1,0x1c(%esp)
804845e: 00
804845f: 8b 44 24 1c mov 0x1c(%esp),%eax
8048463: 89 44 24 04 mov %eax,0x4(%esp)
8048467: c7 04 24 18 85 04 08 movl $0x8048518,(%esp)
Run Code Online (Sandbox Code Playgroud)
作者还说" 我们怎么知道在返回地址中添加8?我们首先使用测试值(例如1) "他在哪里使用此测试值?
我的Mono应用程序在Mac上崩溃并显示此消息(完整日志):
$ mono --debug bin/Debug/SparkleShare.app/Contents/MonoBundle/SparkleShare.exe
[...]
Stack overflow in unmanaged: IP: 0x26eb76, fault addr: 0xbf808ffc
[...]
Run Code Online (Sandbox Code Playgroud)
"in unmanaged"意味着堆栈溢出不在我的代码中(我只有托管代码),而是在我嵌入的库(SQLite,DotCmis,NewtonSoft.Json)或Mono的代码中.
即使我在调试模式下编译并运行,我得到的只是这两个十六进制.
问题:如何调查此堆栈溢出?任何诡计?
注意:相同的库(具有几乎相同的代码)在Linux和Windows上运行良好.
我使用ServiceStack的JsonServiceClient和Silverlight 5从我的ASP.Net服务器接收JSON数据.它适用于简短的JSON字符串,但是当涉及到非常大量的数据时,会抛出StackOverflowException ServiceStack.ServiceClient.Web.AsyncServiceClient.ReadCallBack<>.
所以我检查了GitHub上的最新源代码,并注意到数据是从块中以块状方式读取的,大小为4096字节.问题是这个方法读取一个块并告诉流完成后递归调用自身.我们收到的数据越多,发生的递归调用就越多.这就是当接收到的数据太大时应用程序崩溃的原因.
思路:
无论如何,在我下载所有源代码,自己修改和编译之前,我想听听你对此的看法.这是一个错误还是我错了?
堆栈溢出的原因是因为堆栈空间耗尽,但是如果函数没有参数,那么没有数据必须被压入堆栈呢?这仍然会推动"返回"地址,但在预期无限递归的情况下,这是不必要的.
所以我猜的是......是否有可能使用某种调用约定,调用不会在堆栈上放任何东西,只是跳转到第一条指令并执行并提供最终指令将是另一个函数调用,直到最终执行终止?理想情况下,如果可以使用函数指针和动态链接实现这一点?
只是为了指定,我指的是一个接受单个参数并且什么都不返回的函数,所以技术上fastcall就足够了,但它仍然保留了一个返回的地址,最终会导致溢出.这可以通过某种方式加以预防吗?
我之前没有提到的另一个重点,我不是指单个函数的递归,例如状态是静态的并且正在被重用,我的意思是从一个任意函数递归到另一个函数.
我在Debian OS上运行一个带递归调用的程序.我的堆栈大小是
-s: stack size (kbytes) 8192
Run Code Online (Sandbox Code Playgroud)
据我所知,堆栈大小必须是固定的,并且必须与每次运行时必须分配给程序的相同,除非明确更改它ulimit.
递归函数是递减给定的数字,直到达到0.这是用Rust写的.
fn print_till_zero(x: &mut i32) {
*x -= 1;
println!("Variable is {}", *x);
while *x != 0 {
print_till_zero(x);
}
}
Run Code Online (Sandbox Code Playgroud)
并且值传递为
static mut Y: i32 = 999999999;
unsafe {
print_till_zero(&mut Y);
}
Run Code Online (Sandbox Code Playgroud)
由于分配给程序的堆栈是固定的,理论上不能改变,我每次都希望堆栈溢出的值相同,但不是,这意味着堆栈分配是可变的.
运行1:
====snip====
Variable is 999895412
Variable is 999895411
thread 'main' has overflowed its stack
fatal runtime error: stack overflow
Run Code Online (Sandbox Code Playgroud)
运行2:
====snip====
Variable is 999895352
Variable is 999895351
thread 'main' has overflowed its stack
fatal …Run Code Online (Sandbox Code Playgroud) 注1:这里的CPS代表“持续通过风格”
我对了解如何挂接到C#异步机制非常感兴趣。基本上,据我了解的C#异步/等待功能,编译器将执行CPS转换,然后将转换后的代码传递给上下文对象,该对象管理各个线程上的任务调度。
您是否认为可以利用该编译器功能来创建功能强大的组合器,同时又保留默认的线程方面?
一个例子就是可以递归和记忆诸如
async MyTask<BigInteger> Fib(int n) // hypothetical example
{
if (n <= 1) return n;
return await Fib(n-1) + await Fib(n-2);
}
Run Code Online (Sandbox Code Playgroud)
我设法做到这一点:
void Fib(int n, Action<BigInteger> Ret, Action<int, Action<BigInteger>> Rec)
{
if (n <= 1) Ret(n);
else Rec(n-1, x => Rec(n-2, y => Ret(x + y)));
}
Run Code Online (Sandbox Code Playgroud)
(不使用异步,非常笨拙...)
或使用monad(While<X> = Either<X, While<X>>)
While<X> Fib(int n) => n <= 1 ?
While.Return((BigInteger) n) :
from x in Fib(n-1)
from y in Fib(n-2) …Run Code Online (Sandbox Code Playgroud) c# stack-overflow combinators continuation-passing async-await
stack-overflow ×10
c ×3
c# ×3
.net ×2
recursion ×2
async-await ×1
c++ ×1
clojure ×1
combinators ×1
disassembly ×1
ghc ×1
haskell ×1
linux ×1
mono ×1
monodevelop ×1
monomac ×1
pragma ×1
runtime ×1
rust ×1
servicestack ×1
silverlight ×1
stack ×1
stack-trace ×1
unmanaged ×1