I’ve found a memory leak in some FFI code. I’ll give example code
below, but I can explain the issue easily enough first.
When calling a function provided by Tokyo Cabinet, it returns a value in
the form of a pointer and a length to read at that address. The
documentation for the function (tchdbget() at
http://1978th.net/tokyocabinet/spex-en.html#tchdbapi, if you are
interested) warns that the returned region was allocated with malloc()
and needs to be free()d. I can’t figure out how to free the value, so
there is a memory leak. What I would like to know is how to free the
value at the end of the pointer.
Here’s some code showing what I just explained.
#!/usr/bin/env ruby -wKU
require “rubygems”
require “ffi”
map the C interface
module Lib
extend FFI::Library
ffi_lib(
Array(
ENV.fetch(
“TOKYO_CABINET_LIB”,
Dir["/{opt,usr}/{,local/}lib{,64}/libtokyocabinet.{dylib,so}"]
)
)
)
attach_function :tchdbnew, [ ],
:pointer
attach_function :tchdbopen, [:pointer, :string, :int],
:bool
attach_function :tchdbput, [:pointer, :pointer, :int, :pointer,
:int],
:bool
attach_function :tchdbget, [:pointer, :pointer, :int, :pointer],
:pointer
attach_function :tchdbclose, [:pointer],
:bool
end
translate the interface to Ruby
class TokyoCabinet
def self.open(*args)
db = new(*args)
yield db
ensure
db.close if db
end
def initialize(path)
@db = Lib.tchdbnew
Lib.tchdbopen(@db, path, (1 << 1) | (1 << 2)) # write create mode
end
def []=(key, value)
k, v = key.to_s, value.to_s
Lib.tchdbput(@db, k, k.size, v, v.size)
end
def
k = key.to_s
size = FFI::MemoryPointer.new(:int)
value = Lib.tchdbget(@db, k, k.size, size)
value.address.zero? ? nil : value.get_bytes(0, size.get_int(0))
ensure
size.free if size
# FIXME: How do I free value here?
end
def close
Lib.tchdbclose(@db)
end
end
show the problem
def show_memory
3.times { GC.start } # try to clean up
mem = ps -o rss -p #{Process.pid}
[/\d+/]
puts “Current memory: #{mem}”
end
TokyoCabinet.open(“leak.tch”) do |db|
db[:some_key] = “X” * 1024
10.times do
5000.times do
db[:some_key] # reading causes the memory leak
end
show_memory
end
end
Sample Run:
Current memory: 30324
Current memory: 37828
Current memory: 45364
Current memory: 52896
Current memory: 60428
Current memory: 67960
Current memory: 75488
Current memory: 83020
Current memory: 90552
Current memory: 98080
END
Thanks in advance for any help provided.
James Edward G. II