固定長メモリプール

メモリの確保を頻繁に行うようなアプリケーションでは、固定長のメモリプールを使うと早くなるかなーと思ってとりあえず実装してみました。nextって名前のsetter/getterがあればなんでもメモリプールに入れることができます。でも自分でfreeを呼ばないといけないのは面倒。むー。で、肝心の性能については検証してません。ダメじゃん。

class MemoryPool
  def initialize(cell, size)
    @pool = Array.new(size) { cell.dup }
    (size - 1).times do |i|
      @pool[i].next = @pool[i + 1]
    end
    @pool[-1] = nil
    @free_list_top = @pool[0]
  end

  def alloc
    raise "can't alloc cell." unless @free_list_top
    cell = @free_list_top
    @free_list_top = cell.next
    cell.next = nil
    cell
  end

  def free(cell)
    raise 'double free.' if cell.next
    cell.next = @free_list_top
    @free_list_top = cell
  end

  def free_space_num
    n = 0
    cell = @free_list_top
    while cell
      n += 1
      cell = cell.next
    end
    n
  end
end

if __FILE__ == $0
  class Cell
    attr_accessor :next
  end
  
  pool = MemoryPool.new(Cell.new, 4)

  cell = pool.alloc
  printf "free_space_num=%s, cell=%s\n", pool.free_space_num, cell
  # => free_space_num=3, cell=#<Cell:0x8074f00>

  cell = pool.alloc
  printf "free_space_num=%s, cell=%s\n", pool.free_space_num, cell
  # => free_space_num=2, cell=#<Cell:0x8074eec>

  pool.free(cell)
  cell = pool.alloc
  printf "free_space_num=%s, cell=%s\n", pool.free_space_num, cell
  # => free_space_num=2, cell=#<Cell:0x8074eec>

  cell = pool.alloc
  printf "free_space_num=%s, cell=%s\n", pool.free_space_num, cell
  # => free_space_num=1, cell=#<Cell:0x8074ed8>

  cell = pool.alloc
  printf "free_space_num=%s, cell=%s\n", pool.free_space_num, cell
  # => free_space_num=0, cell=#<Cell:0x8074ec4>
end