Subject:
Re: [ruby-ffi] Proper memory management
From:
v01d
Date:
5/5/10 9:02 PM
To:
ruby-ffi@googlegroups.com

Well, as I said in this case I can't use block-form.

Relying on the MRI GC is no problem, just that I would need this to be called when the object is freed, not just finalized, which can be a while later. This is perfectly do-able with the C API, its just that I don't know if any other FFI user has a better way to solve this without resorting to C.

On 05/05/2010 10:02 PM, Jeremy Voorhis wrote:
I know from discussions over irc that Evan Phoenix isn't too keen on
using finalizers for memory management for this very reason. In my own
projects, I've found myself occasionally writing #dispose methods for
manual object deletion, along with a block form of the constructor that
ensures #dispose is called after the block is run. If controlling when
memory should be freed is important, it's probably best not to rely on
MRI's GC!

Best

Jeremy

On Wed, May 5, 2010 at 3:56 PM, v01d <phreakuencies@gmail.com
<mailto:phreakuencies@gmail.com>> wrote:

    Hi,
    I'm in the process of developing a Ruby binding to the GSL numerical
    library using FFI. Recently I stumbled upon a problematic issue
    regarding memory management and finalizers.

    Since the GSL library allows creation and destruction of instances
    like this:
    gsl_vector* ptr = gsl_alloc_vector(size_t n);
    ...
    gsl_free_vector(ptr);

    Then, in Ruby I do something like this:

    class Vector
      def initialize(n)
        @ptr = GSLng.backend.gsl_alloc_vector(n)
        Vector.define_finalizer(self, @ptr)
      end

      def Vector.define_finalizer(self, ptr)
        ObjectSpace.define_finalizer(self, lambda {|id|
    GSLng.backend.gsl_free_vector(ptr)})
      end
    end

    The problem is that if later I instatiante a Vector inside a loop,
    like:
    10000.times do
      Vector.new(3)
    end

    This obviously eats a lot of memory until GC runs. Now, if I do:
    10000.times do
      Vector.new(3)
      GC.start
    end

    the memory that the Vector instances themselves occupy is freed but
    the finalizer is not called (it is later called at program end),
    therefore all of the memory allocated through gsl_alloc_vector() is
    sitting there until program ends.

    I know that Ruby doesn't guarantee that finalizers are called in any
    particular moment (even after GC.start, which I thought would
    suffice). So what I'm asking probably is not really related to FFI
    itself, but I wanted to ask here since I imagined this would be a
    common pattern among FFI users. The question is then: is there a
    better way to manage this type of memory? I obviously cant use the
    transaction-like pattern (like File.open) since for a Vector that
    wouldn't make sense. It would be ideal to make the gsl_vector_free
    call when the actual Vector class is free'd. Maybe I need to go to a
    lower level for this and use the C api to register this call in the
    "free" function for this class, but that would be overkill since I
    wanted to avoid using C altogether.

    Thank you!