从 OCaml 中的软内存不足错误中恢复

Recovering from soft out-of-memory errors in OCaml

我正在用 OCaml 编写符合 ISO 标准的 Prolog 系统。为了符合 ISO/IEC 13211-1:1995,实现必须正确处理内存不足的情况:

7 Language concepts and semantics

7.12 Errors

7.12.2 Error classification

h) There shall be a Resource Error at any stage of execution when the processor has insufficient resources to complete execution. It has the form resource_error(Imp_dep_atom) where Imp_dep_atom denotes an implementation dependent term.

因此符合 ISO 标准的 Prolog 系统必须提供以下三个功能:

  1. resource_error(memory) 在 运行 超出堆 space 时抛出。
  2. resource_error(stack) 在 运行 退出调用堆栈时抛出。
  3. 这两个异常都可以在 Prolog 中使用内置的 catch/3.
  4. 捕获

到目前为止,一切顺利!在 "Today's trick : memory limits with Gc alarms" [discuss.ocaml.org] 的帮助下,我能够实施 soft(应用程序级别)内存限制。

当我连续多次 运行 一个特定的查询(需要 ~60% 的内存指定为软限制)时,但是, 一些有趣的事情正在发生: 我每隔一段时间就会得到一个答案,并且 运行 每隔一段时间就会内存不足。

就 ISO 一致性而言,这种行为是可以的,但我宁愿每次都得到答案,也不愿每隔一段时间得到答案。呸!

这应该是可行的,特别是如果我达到的限制是 soft(在 OCaml 级别上自行施加)。

所以:我怎样才能强制 OCaml GC 做(甚至)比 Gc.compact 更多的工作?

您可能正在寻找类似的东西:

Gc.set {Gc.get () with Gc.space_overhead = 40}

Gc.compact 是一次性解决方案:GC 在您调用它时会做一些工作以释放 space。而且你不能让 GC 做比 Gc.compact 更多的一次性工作,以释放更多内存。在Gc.compact ()之后,只有OCaml为堆保留的内存块中存在实时数据,如果保留的内容比实际需要的太多,则释放不需要的块等

你想要的可能是 GC 永久花费更多的时间以使用更少的内存。您可以通过设置 space_overhead 参数(可能 max_overhead)来获得该行为。详情见relevant chapter of the OCaml documentation

type control = { … mutable space_overhead : int; (*
The major GC speed is computed from this parameter. This is the memory that will be "wasted" because the GC does not immediately collect unreachable blocks. It is expressed as a percentage of the memory used for live data. The GC will work more (use more CPU time and collect blocks more eagerly) if space_overhead is smaller. Default: 80.

同一章中记录的其他 GC 参数也可能间接影响内存消耗。这完全取决于您愿意用什么来换取更少的内存使用。