camillobruni
camillobruni

Reputation: 2318

luajit qsort callback example memory leak

I have the following qsort example to try out callbacks in luajit. However it has a memory leak (luajit: not enough memory when executing) which is not obvious to me.

Can somebody give me some hints on how to create a proper callback example?

local ffi = require("ffi")

-- ===============================================================================

ffi.cdef[[
    void qsort(void *base, size_t nel, size_t width, int (*compar)(const void *, const void *));
]]


function compare(a, b)
    return a[0] - b[0] 
end

-- ===============================================================================

-- Explicitly convert to a callback via cast
local callback = ffi.cast("int (*)(const char *, const char *)", compare)

local data     = "efghabcd"
local size     = 8 
local loopSize = 1000 * 1000 * 100.

local bytes    = ffi.new("char[15]")

-- ===============================================================================

for i=1,loopSize do 
    ffi.copy(bytes, data, size)
    ffi.C.qsort(bytes, size, 1, callback)
end

Platform: OSX 10.8 luajit: 2.0.1

Upvotes: 3

Views: 962

Answers (1)

greatwolf
greatwolf

Reputation: 20858

The problem appears to be that lua never gets a chance to perform a full garbage collection cycle inside the tight loop. As hinted by the comment, you can correct this by calling collectgarbage() yourself inside the loop.

Note that calling collectgarbage() on every iteration will impact the running time of whatever you're benching. To minimize this, you should set a threshold to limit how often collectgarbage() gets called:

local memthreshold = 2 ^ 20 / 1024
local start = os.clock()
for i = 1, loopSize do
    ffi.copy(bytes, data, size)
    ffi.C.qsort(bytes, size, 1, callback)
    if collectgarbage'count' > memthreshold then
      collectgarbage()
    end
end
local elapse = os.clock() - start
print("elapsed:", elapse..'s')

Upvotes: 1

Related Questions