Hello,
I have a problem concerning the memory usage of BigFloats.
I have quite some trouble switching a self-written ODE solver as well as DifferentialEquations.jl (less tests with that) from Float64
to BigFloat
because of drastically increasing memory consumption. Calculations which would require only around 1 GByte with Float64
would suddenly spiral out of control even with 64 bit mantissa BigFloats consuming more than 12 GByte (on a 16 GByte machine). Now, certainly BigFloats must have quite some overhead compared to a Float64, but still.
To better understand what was happening I constructed this MWE which is essentially what a Euler ODE solver would do:
setprecision(64)
CalcType=BigFloat
function rhs(t::T,x::Array{T,1}) where {T}
back=zeros(T,3)
back[1]=x[2]
back[2]=-sin(x[1])
back[3]=T(0.2)
return back
end
function mtest!(out::Array{T,2},dt::T) where {T}
for ii=2:size(out,2)
vect=rhs(T(0.0),out[:,ii-1])
for jj=1:length(vect)
out[jj,ii]=out[jj,ii-1]+dt*vect[jj]
end
end
return nothing
end
out=zeros(CalcType,3,10000000);
out[:,1]=[CalcType(0.25),CalcType(0.0),CalcType(0.0)]
mtest!(out,CalcType(1//100))
Running this in the REPL or, to make measuring memory easier, non-interactive uses roughly 4 GByte of memory according to /usr/bin/time
and checked with top
:
% /usr/bin/time ~/bin/julia-1.0.4/bin/julia mtest_loop.jl
39.25user 1.68system 0:40.97elapsed 99%CPU (0avgtext+0avgdata 4030852maxresident)k
8inputs+0outputs (0major+1454329minor)pagefaults 0swaps
Same with 1.3rc3.
Running mtest!(out,CalcType(1//100))
twice instead of once gives
% /usr/bin/time ~/bin/julia-1.0.4/bin/julia mtest_loop.jl
86.74user 2.40system 1:29.15elapsed 99%CPU (0avgtext+0avgdata 4393876maxresident)k
8inputs+0outputs (0major+2091832minor)pagefaults 0swaps
This appears to be quite excessive. Naively one could expect that the array out
in the MWE uses about 3*10000000*8/1024/1024=228 MByte
, although BigFloats probably have quite some overhead. What would be the expected in-memory size of the out[]
array above with BigFloats ?
Forcing garbage collection by replacing the mtest!()
function above with this
function mtest_gc!(out::Array{T,2},dt::T) where {T}
for ii=2:size(out,2)
vect=rhs(T(0.0),out[:,ii-1])
for jj=1:length(vect)
out[jj,ii]=out[jj,ii-1]+dt*vect[jj]
end
if (mod(ii,100000)==0.0)
GC.gc()
end
end
return nothing
end
reduces memory consumption considerably to only 2.8 GByte but with a huge run-time penalty:
% /usr/bin/time ~/bin/julia-1.0.4/bin/julia mtest_loop_gc.jl
317.42user 1.38system 5:18.90elapsed 99%CPU (0avgtext+0avgdata 2856636maxresident)k
8inputs+0outputs (0major+1219701minor)pagefaults 0swaps
One can of course change the CalcType
from BigFloat
to Float64
in the original MWE. Total memory usage is then about 430 MByte.
From this I believe that the garbage collector is not doing a very good job for BigFloats. Is this true ? Is there anything I can tune apart from manually forcing garbage collection to stop memory consumption before the machine swaps to death ? This is especially important for DifferentialEquations.jl where it is not really possible to force garbage collection manually.