I’m creating and saving a series of images using PyPlot and savefig. However, despite using ioff() and closing all the figures, the memory increases linearly with number of figures that are created, saved and closed. I upgraded to the latest julia 1.5.2 and pkg> up and that did not solve the problem. Does anyone experience the same problem or preferably have a solution or workaround? Below is a MWE:
using PyPlot
ioff()
for i = 1:2000
println(i)
figure()
plot(randn(30000))
savefig("figure_$i.png")
close()
end
I thought close() did that, i.e. closed the most recently opened figure. Even if I do figure(1) and close(1) or close("all") I experience the same issue unfortunately.
Yes but I thought that would release with close(). I tried use an existing array created outside the for loop but still the same problem. There seems to be some other reason, if I remove both the plot and the savefig part it still increases memory linearly, but with a slower rate. Somehow the memory is not released with close() or plt.cla() or plt.clf().
It does seem like the julia version is retaining more memory than the pure python version. Without digging much deeper I suspect PyCall isn’t handling cross-language circular reference well.
Would it be possible to call the python garbage collector to clear the memory? I have some rather large plots and have to close Julia to free up memory between plot sets so I don’t get an error.
If a new reference is returned by a Python function, immediately convert the PyPtr return values to PythonObject objects in order to have their Python reference counts decremented when the object is garbage collected in Julia. i.e. PythonObject(ccall(func, PyPtr, ...)) . Important : for Python routines that return a borrowed reference, you should instead do pyincref(PyObject(...)) to obtain a new reference.
You can call pyincref(o::PyObject) and pydecref(o::PyObject) to manually increment/decrement the reference count. This is sometimes needed when low-level functions steal a reference or return a borrowed one.
I found a workaround: if I add a GC.gc() inside the loop the memory is released. However, it has no effect (i.e. the memory is not released) if I add it outside and after the loop. Also, note that GC.gc() can be added anywhere in the loop and memory is released (perhaps something to do with the local scope).
using PyPlot
ioff()
for i = 1:2000
println(i)
figure()
plot(randn(30000))
savefig("figure_$i.png")
close()
GC.gc()
end