val add_finalizer : 'a Heap_block.t -> ('a Heap_block.t -> Base.Unit.t) -> Base.Unit.tadd_finalizer b fensures thatfruns afterbbecomes unreachable. The OCaml runtime only supports finalizers on heap blocks, henceadd_finalizerrequiresb : _ Heap_block.t. The runtime essentially maintains a set of finalizer pairs:'a Heap_block.t * ('a Heap_block.t -> unit)Each call to
add_finalizeradds a new pair to the set. It is allowed for many pairs to have the same heap block, the same function, or both. Each pair is a distinct element of the set.After a garbage collection determines that a heap block
bis unreachable, it removes from the set of finalizers all finalizer pairs(b, f)whose block isb, and then and runsf bfor all such pairs. Thus, a finalizer registered withadd_finalizerwill run at most once.The GC will call the finalisation functions in the order of deallocation. When several values become unreachable at the same time (i.e. during the same GC cycle), the finalisation functions will be called in the reverse order of the corresponding calls to
add_finalizer. Ifadd_finalizeris called in the same order as the values are allocated, that means each value is finalised before the values it depends upon. Of course, this becomes false if additional dependencies are introduced by assignments.In a finalizer pair
(b, f), it is a mistake for the closure offto reference (directly or indirectly)b--fshould only accessbvia its argument. Referring tobin any other way will causebto be kept alive forever, sincefitself is a root of garbage collection, and can itself only be collected after the pair(b, f)is removed from the set of finalizers.The
ffunction can use all features of OCaml, including assignments that make the value reachable again. It can also loop forever (in this case, the other finalisation functions will be called during the execution of f). It can calladd_finalizeronvor other values to register other functions or even itself.All finalizers are called with
Exn.handle_uncaught_and_exit, to prevent the finalizer from raising, because raising from a finalizer could raise to any allocation or GC point in any thread, which would be impossible to reason about.add_finalizer_exn b fis likeadd_finalizer, but will raise ifbis not a heap block.
val add_finalizer_exn : 'a -> ('a -> Base.Unit.t) -> Base.Unit.tval add_finalizer_last : 'a Heap_block.t -> (Base.Unit.t -> Base.Unit.t) -> Base.Unit.tSame as
add_finalizerexcept that the function is not called until the value has become unreachable for the last time. This means that the finalization function does not recieve the value as an argument. Every weak pointer and ephemeron that contained this value as key or data is unset before running the finalization function.
val add_finalizer_last_exn : 'a -> (Base.Unit.t -> Base.Unit.t) -> Base.Unit.tval finalize_release : Base.Unit.t -> Base.Unit.tThe runtime essentially maintains a bool ref:
val finalizer_is_running : bool refThe runtime uses this bool ref to ensure that only one finalizer is running at a time, by setting it to
truewhen a finalizer starts and setting it tofalsewhen a finalizer finishes. The runtime will not start running a finalizer if!finalizer_is_running = true. Callingfinalize_releaseessentially doesfinalizer_is_running := false, which allows another finalizer to start whether or not the current finalizer finishes.
module Alarm : sig ... endA GC alarm calls a user function at the end of each major GC cycle.