I have a data type that holds pointers to C data (for passing to a library):
mutable struct Data
ptr::Array{Ptr{Int},1}
end
When a Data
object is released, I want to perform some operations on the pointers to free the corresponding memory (i.e. pass them to some function in my C library). The first thought would be to attach a finalizer function in the constructor such as this:
Data(...) = begin
self = ... # perform initialization and then
finalizer(kill, self)
end
kill(x::Data) = begin
# release C pointers here
end
However, in my case some of the C pointers might be referenced by multiple Data
objects. This means that I cannot simply free them each time a Data
object becomes inaccessible Julia-side.
I can imagine one and a half way to do this:
- the first way would be to manually implement reference-counting for the C pointers (increment refcount in the constructor, decrement it in the finalizer);
- the second one would be to somehow attach the pointers to Julia’s tracing GC.
The second way feels more elegant/efficient, but I’m not quite sure how to do this. Maybe I could wrap a trivial Julia type around the C pointer, make my Data
struct contain pointers to these wrappers (keeping these alive as long as the Data
is), and then do the pointer freeing at the wrapper level? How then can I be sure that, if a certain pointer is referenced more than once, all the wrappers will be the same Julia object (and thus the finalizer will only be invoked when the last one of them dies)? Should I make the wrappers Val{my_pointer}()
values?
Thanks,