Search code examples
garbage-collectioncommon-lispfinalizer

How can I get the Lisp garbage collector to remove foreign c++ allocated memory in my class slots?


My class looks like this:

(defclass matrix ()
  ((rows :initarg :rows :initform 2)
   (cols :initarg :cols :initform 2)
   (matrix :accessor matrix)))

I have a specialisation of the initialize-instance method which creates the object for the matrix slot by calling into a c++ library. I have a matrix-destroy function which will free the memory allocated in c++.

What I want is to be able to get the garbage collector to call matrix-destroy on the matrix slot. Is there an idiomatic way to do this in common lisp?


Solution

  • In order to run a function after the garbage collector has collecte an object, you need to set a finalizer for that object. The Common Lisp standard does not include finalizers, but implementations do provide them. There is a compatibility library called Trivial Garbage that you can use to set them portably.

    Setting a finalizer happens by simply calling FINALIZE on the object you want to attach the finalizer to. The finalizer function must not contain any references to the object itself, as that would prevent it from ever being collected. You should also keep in mind that the finalizer may be executed at any time in any thread, so it should be re-entrant and not depend on any specific dynamic environment.

    SBCL manual has a short example for finalizers in 7.4 Garbage Collection. You can also see some existing project that uses them, such as cl-sdl2, which uses them to free SDL surfaces, textures and such. See SDL-COLLECT for where the finalizer is set, and CREATE-RGB-SURFACE for an example of where SDL-COLLECT is called from.