我正在使用这段代码并且将触发stackoverflow,如果我使用Extlib的Hashtbl,则不会发生错误。有没有stackoverflow使用专门的Hashtbl的任何提示?
module ColorIdxHash = Hashtbl.Make(
struct
type t = Img_types.rgb_t
let equal = (==)
let hash = Hashtbl.hash
end
)
(* .. *)
let (ctable: int ColorIdxHash.t) = ColorIdxHash.create 256 in
for x = 0 to width -1 do
for y = 0 to height -1 do
let c = Img.get img x y in
let rgb = Color.rgb_of_color c in
if not (ColorIdxHash.mem ctable rgb) then ColorIdxHash.add ctable rgb (ColorIdxHash.length ctable)
done
done;
(* .. *)
回溯指向hashtbl.ml:
致命错误:异常Stack_overflow在文件“hashtbl.ml”处引发, 第54行,字符16-40从文件“img / write_bmp.ml”,行调用 150,字符52-108 ......
任何提示?
答案 0 :(得分:5)
嗯,您正在使用物理相等(==)来比较哈希表中的颜色。如果颜色是结构化值(我无法从这段代码中得知),它们中的任何一个都不会在物理上彼此相等。如果所有颜色都是不同的对象,它们都将进入表格,这可能是相当多的对象。另一方面,散列函数将基于实际颜色R,G,B值,因此可能存在大量重复。这意味着您的哈希桶将具有非常长的链。也许某些内部函数不是尾递归,因此堆栈溢出。
通常,最长链的长度为2或3,因此不会经常出现此错误也不足为奇。
查看我的hashtbl.ml(OCaml 3.12.1)的副本,我在第54行看不到任何非尾递归的东西。所以我的猜测可能是错的。在第54行,为哈希表分配新的内部数组。所以另一个想法就是你的哈希表太大了(可能是由于不必要的重复)。
要尝试的一件事是使用结构相等(=)并查看问题是否消失。
答案 1 :(得分:1)
如果您的类型包含循环值,则可能出现非终止或堆栈溢出的一个原因。 (==)
将终止于循环值(虽然(=)
可能不会),但Hash.hash
可能不是循环安全的。因此,如果您操作类型Img_types.rgb_t
的循环值,则必须设计一个循环安全散列函数 - 通常只在值的一个非循环子字段/子组件上调用Hash.hash
。
过去我已经被这个问题所困扰了。追踪并不是一个有趣的错误。