I’ve done some more digging running the following code, which should not be suffering from the fork bomb with while true, and is thus closer to my real world case:
function meminfo_julia!(d)
push!(d["GC Live"], Base.gc_live_bytes()/2^20)
push!(d["Max. RSS"], Sys.maxrss()/2^20)
end
function meminfo_procfs(d)
pid=getpid()
smaps = "/proc/$pid/smaps_rollup"
if !isfile(smaps)
error("`$smaps` not found. Maybe you are using an OS without procfs support or with an old kernel.")
end
rss = pss = shared = private = 0
for line in eachline(smaps)
s = split(line)
if s[1] == "Rss:"
rss += parse(Int64, s[2])
elseif s[1] == "Pss:"
pss += parse(Int64, s[2])
end
end
push!(d["RSS"], rss/2^10)
push!(d["PSS"], pss/2^10)
end
function explode(buffer = IOBuffer())
lck = ReentrantLock()
path = "test.log"
@sync for _ in 1:1000000
Threads.@spawn begin
lock(lck) do
println(buffer, "blabla")
open(path, append=true) do f
write(f, take!(buffer))
end
end
end
end
end
memdict = Dict("GC Live" => Float64[],
"Max. RSS" => Float64[],
"RSS" => Float64[],
"PSS" => Float64[])
t = Threads.@spawn let
buffer = IOBuffer()
for i = 1:200
explode(buffer)
meminfo_julia!(memdict)
meminfo_procfs(memdict)
end
end
Which takes ages, but produces:
So while the memory consumption seems to stabilize around 6Gb, this is actually not quite true as it keeps trending upwards slowly but surely. I think this is exactly the leak I’m seeing in my real world case.
I’d love to get some more insights on what might be going on here