OCaml 本机代码上升堆栈溢出字符串



我正在做一个OCaml项目,该项目似乎有一些计算效率问题。在试图找到瓶颈时,出于好奇,我尝试编译为本机代码而不是字节码,想知道运行时间会有多大差异。

事实证明,本机代码会引发堆栈溢出。我尝试使用OCAMLRUNPARAM=b执行,但我没有得到太多关于堆栈跟踪的信息:

Fatal error: exception Stack overflow
Raised at file "map.ml", line 122, characters 10-25
Called from file "str.ml", line 259, characters 6-29

仅此而已。我不知道我的代码中导致它的意义何在。此外,我的程序不使用大字符串,所以我不明白为什么Str应该去堆栈溢出......

是否有一些参数可以调整来调查问题?

溢出是由嵌套函数调用的深度引起的,而不是由所涉及的字符串的长度引起的。

除此之外,您没有提供足够的信息来提供帮助。您的项目中是否有名为"map.ml"的文件?第 122 行周围是什么样子的?

如果项目中没有名为"map.ml"的文件,则可能会在标准库中看到函数的非尾递归行为。特别是,我猜问题出在Str模块中正则表达式的编译中。您是否有任何异常大的正则表达式?

如果使用-g构建代码(例如,如果使用 ocamlbuild,则通过在_tags中添加true: debug(,您将在堆栈跟踪中获得代码的调试信息(而不仅仅是标准库(。这应该为您提供有关该问题的更多信息。

OCAMLRUNPARAM控制 OCaml 解释器的堆栈大小,与编译的代码无关,编译的代码由操作系统加载器运行,因此您需要使用操作系统来控制堆栈的大小。提示,在 UNIX 中,您可以使用ulimit来设置堆栈大小。

查明堆栈溢出源的问题在于,堆栈的默认大小允许如此大的痕迹,以至于默认堆栈溢出打印机无法将其打印到源,因此诀窍实际上是限制堆栈大小,请参阅我另一个答案中的完整解释。

当然,此外,您还需要 (i( 使用-g选项构建源代码,以及 (ii( 启用堆栈跟踪(取决于编译器版本和使用的库,默认情况下可能会也可能不会启用(。前者特定于您的构建系统,后者可以通过设置OCAMLRUNPARAM=b环境变量(适用于字节码和本机代码(或在应用程序开始时显式调用源代码中的Printexc.record_backtrace true来完成。

这些是一般说明。但是,在您的情况下,映射调用很可能导致堆栈溢出。在 OCaml 标准库中,List.map不是尾递归的,因此您可以考虑将所有List.map xs替换为List.rev (List.rev_map xs),或者如果元素顺序无关紧要,则仅用List.rev_map替换。

最新更新