On Thu, Nov 13, 2014 at 07:54:28PM +0100, Mike Pall wrote: > ffi.gc() only attaches to the cdata pointer object you pass to it. > Only the lifetime of this *object* decides when the finalizer is > called. It doesn't matter which other pointers you have around > that point to the same address. > > Oh, and ... maybe you missed it, because my answer was so lengthy, > but 'event' is unanchored. Anything can happen if you do that. 'event' is only a temporary array that receives the value that is then used to construct the cdata object. The finalizer is attached to that cdata object. Let me clarify the (non-self-contained) example: ffi.cdef[[ typedef void *cl_event; ]] local function enqueue_marker(queue) local event_ptr = ffi.new("cl_event[1]") assert(C.CL_SUCCESS == C.clEnqueueMarker(queue, event_ptr)) local event = ffi.new("cl_event", event_ptr[0]) return ffi.gc(event, release_event) end local queue = ... for i = 1, 100000 do collectgarbage() -- sporadic duplicate finalization of previous event object local event = enqueue_marker(queue) end Why is the finalizer sometimes called twice when cl_event is a pointer type? Thanks, Peter