我正在为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
Run Code Online (Sandbox Code Playgroud)
如果我运行上面的代码,它告诉我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
Run Code Online (Sandbox Code Playgroud)
然后
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
Run Code Online (Sandbox Code Playgroud)
两者都没有 运行Out_of_memory.
这是我的问题:
从我的基准代码,是的,我做了串行排序:mergesort然后快速排序.
在执行期间,应该创建3个主要列表:l来自mergesort的列表和来自quicksort的列表.
但是,从mergesort创建的列表应该GCed在quicksort 之前,对吧?那个清单没有任何参考,对吧?
在quicksort之前,原来只有一个主要列表,对l吧?
为什么它仍然会Out_of_memory出错?
我认为问题在于您使用的列表非常大。垃圾收集器保留两个不同的堆来管理内存:
小堆会定期清除,如果对象存活的时间足够长,则会将其提升到主堆。
然而,真正大的对象会直接进入主堆。问题是主堆需要停止世界,即停止应用程序。因此,主堆收集是分几个步骤完成的,以确保应用程序不会长时间停止,并且不像次要堆收集那样频繁地进行。
也许在你的情况下,当你开始快速排序时,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
Run Code Online (Sandbox Code Playgroud)