Understanding finalizers


#1

Hi all,

I am trying to understand how Julia decides when to call finalizers. I am using MathGL.jl for some plotting, and Julia doesn’t run the required finalizers for MGLGraphs until the end of the script, which makes it run out of memory and be killed when the amount of work becomes non-trivial.

The MathGL wrapper is huge, so I have a toy example below:

# File: memhungry.jl
type MemHungry
bite::Array{Int, 1}
end

function MemHungry(bitesize::Int)
    info("A big bite of memory is now gone...")
    m = MemHungry(Array{Int, 1}(bitesize))
    finalizer(m, memregurgitate)

    return m
end

function memregurgitate(m::MemHungry)
    info("Wow, those blocks of memory sure tasted bad!")
    info("Regurgitating.... Please wait.")
    sleep(1)
    info("Regurgitated $(length(m.bite)*8) bytes")
end

import Base.show
function show(io::IO, m::MemHungry)
    for i in 1:length(m.bite)
        info("Crunch, crunch crrunch!")
    end
end


function munchmem(mealsize::Int)
    m = MemHungry(mealsize)
    info(m)
#    finalize(m)
end

for i in 1:3
    munchmem(i)
end

julia memhungry.jl results in

INFO: A big bite of memory is now gone...
INFO: Crunch, crunch crrunch!
INFO: 
INFO: A big bite of memory is now gone...
INFO: Crunch, crunch crrunch!
INFO: Crunch, crunch crrunch!
INFO: 
INFO: A big bite of memory is now gone...
INFO: Crunch, crunch crrunch!
INFO: Crunch, crunch crrunch!
INFO: Crunch, crunch crrunch!
INFO: 
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF
jl_uv_writecb() ERROR: bad file descriptor EBADF

If I uncomment the call to finalize(m) in munchmem, the output is

INFO: A big bite of memory is now gone...
INFO: MemHungry([0])
INFO: Wow, those blocks of memory sure tasted bad!
INFO: Regurgitating.... Please wait.
INFO: Regurgitated 8 bytes
INFO: A big bite of memory is now gone...
INFO: MemHungry([0,0])
INFO: Wow, those blocks of memory sure tasted bad!
INFO: Regurgitating.... Please wait.
INFO: Regurgitated 16 bytes
INFO: A big bite of memory is now gone...
INFO: MemHungry([0,0,0])
INFO: Wow, those blocks of memory sure tasted bad!
INFO: Regurgitating.... Please wait.
INFO: Regurgitated 24 bytes

So my question: Why does Julia have to be prodded like this to finalize things, even when (as with my plotting) memory is running low? Is there a way to avoid the prodding?

Thanks,

Lewis