我该怎么办才能让GC释放OCaml中未使用的内存?

时间:2013-07-18 14:29:12

标签: ocaml

我正在为mergesort和quicksort做基准测试。

我实施了Random_list.createMergesort.sort_listQuicksort.sort_list。我们可以假设这三个函数都已正确实现,并且在这个问题中实现并不重要。

我想问的是关于OCaml的GC


这是我的基准代码:

let _ = 
  let l = Random_list.create 10000000 in

  let len1 = List.length (Mergesort.sort_list l) in
  Printf.printf "mergesort done for %d elements" len1;

  let len2 = List.length (Quicksort.sort_list l) in
  Printf.printf "quicksort done for %d elements" len2

如果我运行上面的代码,它会在Fatal error: exception Out_of_memory之后告诉我mergesort done for 10000000 elements

内存不足,没问题。成功Out_of_memory后,输出也会告诉我mergesort


然后我做的是拆分代码并单独测试:

let _ = 
      let l = Random_list.create 10000000 in
      let len1 = List.length (Mergesort.sort_list l) in
      Printf.printf "mergesort done for %d elements" len1

然后

let _ = 
      let l = Random_list.create 10000000 in
      let len2 = List.length (Quicksort.sort_list l) in
      Printf.printf "quicksort done for %d elements" len2

两者都运行良好没有 Out_of_memory


以下是我的问题:

从我的基准代码,是的,我做了串行排序:mergesort然后快速排序。

在执行期间,应该创建3个主要列表:l以及mergesort中的列表和来自快速排序的列表。

但是,在quicksort之前,从mergesort创建的列表应该是GCed,对吧?那个清单没有任何参考,对吧?

在快速排序之前,原始l只有一个主要列表,对吗?

为什么它仍然会出现Out_of_memory错误?

2 个答案:

答案 0 :(得分:2)

我认为问题在于您使用的是非常大的列表。垃圾收集器保留两个不同的堆来管理内存:

  • 次要堆,用于小型/短期对象。
  • 主要堆,用于持久对象。

定期清除次要堆,如果对象存活的时间足够长,则会将其提升为主堆。

然而,真正的大对象直接进入主堆。问题是主要的堆需要停止世界,即停止应用程序。因此,主要的堆收集是通过几个步骤完成的,以确保应用程序不会长时间停止,并且也不会像次要堆集合那样频繁地完成。

也许在你的情况下,当你开始快速排序时仍然没有收集merge_sort列表,因此所有3个列表同时存在于内存中。

您可以要求GC进行完整的主要收集,看看它是否能解决问题:

let _ = 
  let l = Random_list.create 10000000 in

  let len1 = List.length (Mergesort.sort_list l) in
  Printf.printf "mergesort done for %d elements" len1;

  Gc.full_major ();

  let len2 = List.length (Quicksort.sort_list l) in
  Printf.printf "quicksort done for %d elements" len2

答案 1 :(得分:2)

很难在不看代码的情况下得出结论,但可能是在第一个程序中,堆栈框架中有Mergesort.sort_list lQuicksort.sort_list l的指针,防止第一个列表成为垃圾收集,而在第二种情况下,堆栈帧在两个let _ = ...

之间解除分配