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:
for i = 1:2000
You are creating a new figure each time with
figure(). Try removing that?
close() did that, i.e. closed the most recently opened figure. Even if I do
close("all") I experience the same issue unfortunately.
What happens if you just remove the
figure() call altogether?
You are creating a new array of random numbers at each step. Why wouldn’t you expect that to allocate memory?
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
That has nothing to do with this.
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.
Yes, you are correct, the equivalent python version of the code (below) does release the memory
from pylab import *
for i in range(1,2001):
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.
Maybe this is helpful from PyCall’s docs:
- 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
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).
for i = 1:2000