Imagine I've a C library called libcat for interacting with my cat fluffy. I'm therefore writing bindings for OCaml to simplify interactions with fluffy.
module type CAT = sig
type cat
val find : ... -> cat
val feed : cat -> unit
...
end ;;
module Cat : CAT = ...
There is considerable memory management already built into libcat, like say caching, freeing destroyed toys, and maybe even a limited scope garbage collector for emptying the litter. Yet, overall libcat requires that users explicitly free unused resources, like lost toys.
I've written a C stub for Cat.find that finds and allocates the cat using libcat's cat_find routine, but then stores the resulting pointer to the cat in a custom block created with caml_alloc_custom.
I've added a finalize method into the custom_operations struct passed into caml_alloc_custom. Crucially, I've made this finalize method free the cat because I'm sick of her scratching on the door while I'm answering a phone exception.
I'm now worried that, if OCaml ever duplicates a custom block of type Cat.cat, then OCaml's garbage collector may free fluffy while we're still playing. For example :
let fluffy = Cat.find ;;
fluffy.yodel ;;
let meow = fluffy ;;
...
meow.feed ;;
We must assume that ... will trigger OCaML's garbage collector after the last explicit reference to fluffy, say by breaking dishes. Is this garbage collection event going to call fluffy's finalize method and free her? Or will meow simply refer to fluffy's original custom block, thus preventing fluffy from being freed?
I'd imagine fluffy isn't freed in this situation, well otherwise OCaml would surely ask for a duplicate method in custom_operations struct, but I felt it better to ask. If fluffy might in fact be freed, can I prevent this by only letting OCaml handle her by reference? Roughly :
type cat_name = real_cat ref
type real_cat
The custom block itself, that is, the bytes obtained from caml_alloc_custom
, is part of the Caml heap and can be moved like any other object.¹ It's very common for the custom block to contain pointers to data structures that are also accessed by C² code and live outside the Caml heap; Caml treats the contents of the custom block as opaque and doesn't even know whether it contains pointers, so it won't touch these data structures.
When you write let meow = fluffy
, there is no copy going on: you're just giving a new name to the same object. Caml will never duplicate a custom block; if you want that, you have to provide a copy_cat
primitive in your library.
¹ Only the minor garbage collector and the compactor actually move blocks around, the major gc doesn't. But that's not something you should rely on.
² Or Fortran, or whatever other language your program or library uses.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With