阴影绑定是否会被GC?

时间:2014-03-25 20:35:12

标签: garbage-collection ocaml

假设我在长期运行的ml文件中有这个:

let l = [1;2;3]

let l = [1;2;3;4]

let _ = ...

第一个l = [1;2;3]会在某个时候被GC?


如果代码如下所示:

let l = [1;2;3]

let l = [1;2;3;4]

let l = [1;2;3]

let _ = ...

有三个l。第1个被第2个阴影,然后第2个被第3个阴影。

以下情况是否可能,因为GC的时间表未确定?

  1. 当达到第3 l时,GC尚未收集第1个[1;2;3],因此重复使用或重新引用相同的内存

  2. 在第二次l之后,GC立即收集了第一个[1;2;3],然后第三个l[1;2;3]

  3. 创建了新内存

2 个答案:

答案 0 :(得分:4)

不在OCaml顶层中,定义新值l不会释放先前的l,其中(据我记得实现)永远存在。它并不重要,因为它是一个常量,只需要与产生它的源代码成比例的空间,就像二进制代码一样。

$ rlwrap ocaml
        OCaml version 4.00.1

# let l = [ 1 ] ;;
val l : int list = [1]
# let w = Weak.create 1 ;;
val w : '_a Weak.t = <abstr>
# Weak.set w 0 (Some l) ;;
- : unit = ()
# Gc.full_major () ;;
- : unit = ()
# Weak.check w 0 ;;
- : bool = true
# 

true means l仍然存在于记忆中。

# let l = [ 2 ] ;;
val l : int list = [2]
# Weak.check w 0 ;;
- : bool = true
# Gc.full_major () ;;
- : unit = ()
# Weak.check w 0 ;;
- : bool = true
# 

它仍然没有,尽管它对于可达的精确定义(不是GC使用的定义)是“不可达的”。

两个编译器都不会释放原始l

$ cat t.ml
let l = [ 1 ] ;;
let w = Weak.create 1 ;;
Weak.set w 0 (Some l) ;;
Gc.full_major () ;;
Printf.printf "%B\n" (Weak.check w 0) ;;
let l = [ 2 ] ;;
Printf.printf "%B\n" (Weak.check w 0) ;;
Gc.full_major () ;;
Printf.printf "%B\n" (Weak.check w 0) ;;
$ ocamlc t.ml
$ ./a.out 
true
true
true
$ ocamlopt t.ml
$ ./a.out 
true
true
true

GC的“可达性”定义的另一个例子比人们可能喜欢的定义更接近:

let g () = Gc.full_major ()

let f () = let l = [ 1 ] in (* do something with l; *) g(); 1

在执行g时(从f调用),不再可以访问值l(对于可到达的精确定义),并且可以进行垃圾回收。它不会是因为它仍然从堆栈中引用。 GC具有可达的粗略概念,只有在f终止后才能释放它。

答案 1 :(得分:3)

取决于你是否仍然在其他地方有引用 - 如果l是唯一引用,那么是,该引用在第二个赋值时释放,并在适当时获得GC。


列表在ocaml中是不可变的; list literals返回新列表实例。

从编程角度来看,你可以对待你的第三个&#34;列表作为一个全新的列表(即使它包含与第一个元素相同的元素)。

从封闭式实现的角度来看,可能是系统足够聪明,知道从第三个分配的第一个列表中重用内存;但是,我无法立即想到一种可行的有效方式,即使用当前编写的代码。

所以,在第三项任务中:

  • 第一个列表可能仍在
  • 从编程的角度来看,它仍将是一个全新的列表
  • 可能但非常不可能的是,系统在封面下知道/能够很好地优化内存使用,以便重用第一次分配的内存。最有可能的是,除非在其他地方引用,否则第一个列表是垃圾收集/将被垃圾收集。

注意

基于@ PascalCuoq的答案,以及一些实验:

如果您将变量定义为顶级变量,则行为会有很大差异。 OCaml垃圾收集器将顶级声明视为(永久?)垃圾收集根 - 因此即使无法再从运行代码中获取它们,它们也不会被GC。

因此,如果上面的例子是在顶级执行的,那么内存中将会有三个不同的&#34; l&#34;&#34;&#39;&#39;&#39;在内存中,没有一个会被垃圾收集。