Not in the OCaml toplevel, defining a new value l
does not free the previous l
, which (as far as I remember the implementation) lives forever. It doesn't matter because it is a constant and only takes space proportional to the source code that engendered it, like binary code does.
$ 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
#
This true
means that l
still lives in memory.
# let l = [ 2 ] ;;
val l : int list = [2]
# Weak.check w 0 ;;
- : bool = true
# Gc.full_major () ;;
- : unit = ()
# Weak.check w 0 ;;
- : bool = true
#
And it still does not, although it is not “reachable” for a fine definition of reachable (not the definition the GC uses).
Neither compiler frees the original l
either:
$ 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
Another example of the GC's definition of “reachability” being more approximative than the definition one might like is:
let g () = Gc.full_major ()
let f () = let l = [ 1 ] in (* do something with l; *) g(); 1
At the point when g
is executed (called from f
), the value l
is no longer reachable (for a fine definition of reachable) and could be garbage-collected. It won't be because it is still referenced from the stack. The GC, with its coarse notion of reachable, will only be able to free it after f
has terminated.