我正在为mergesort和quicksort做基准测试。
我实施了Random_list.create
,Mergesort.sort_list
和Quicksort.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
错误?
答案 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 l
和Quicksort.sort_list l
的指针,防止第一个列表成为垃圾收集,而在第二种情况下,堆栈帧在两个let _ = ...
?