# PyPlot doesn't release mem after close()

**URL:** <https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953>\
**Category:** Visualization\
**Tags:** plotting\
**Created:** [October 7, 2020, 9:00pm UTC](https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953 "2020-10-07T21:00:16Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![JesperMartinsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jespermartinsson/32/34098_2.png) [@JesperMartinsson](https://discourse.julialang.org/u/JesperMartinsson)\
**Post date:** [October 7, 2020, 9:00pm UTC](https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953/1 "2020-10-07T21:00:16Z")

</div>

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:

```julia
using PyPlot
ioff()

for i = 1:2000
    println(i)
    figure()
    plot(randn(30000))
    savefig("figure_$i.png")
    close()
end

```

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [October 7, 2020, 9:31pm UTC](https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953/2 "2020-10-07T21:31:04Z")

</div>

You are creating a new figure each time with `figure()`. Try removing that?

---

<div class="post-metadata">

**Author:** ![JesperMartinsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jespermartinsson/32/34098_2.png) [@JesperMartinsson](https://discourse.julialang.org/u/JesperMartinsson)\
**Post date:** [October 7, 2020, 9:34pm UTC](https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953/3 "2020-10-07T21:34:13Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [October 7, 2020, 9:34pm UTC](https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953/4 "2020-10-07T21:34:45Z")

</div>

What happens if you just remove the `figure()` call altogether?

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [October 7, 2020, 9:35pm UTC](https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953/5 "2020-10-07T21:35:26Z")

</div>

You are creating a new array of random numbers at each step. Why wouldn’t you expect that to allocate memory?

---

<div class="post-metadata">

**Author:** ![JesperMartinsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jespermartinsson/32/34098_2.png) [@JesperMartinsson](https://discourse.julialang.org/u/JesperMartinsson)\
**Post date:** [October 7, 2020, 9:45pm UTC](https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953/6 "2020-10-07T21:45:40Z")

</div>

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()`.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [October 7, 2020, 9:48pm UTC](https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953/7 "2020-10-07T21:48:44Z")

</div>

> [@dpsanders](#):
>
> You are creating a new array of random numbers at each step. Why wouldn’t you expect that to allocate memory?

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.

---

<div class="post-metadata">

**Author:** ![JesperMartinsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jespermartinsson/32/34098_2.png) [@JesperMartinsson](https://discourse.julialang.org/u/JesperMartinsson)\
**Post date:** [October 7, 2020, 10:19pm UTC](https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953/8 "2020-10-07T22:19:11Z")

</div>

Yes, you are correct, the equivalent python version of the code (below) does release the memory

```julia
from pylab import *
ioff()
for i in range(1,2001):
  figure()
  plot(randn(30000))
  savefig("figure_"+str(i)+".png")
  close()

```

---

<div class="post-metadata">

**Author:** ![Daneel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/daneel/32/175_2.png) [@Daneel](https://discourse.julialang.org/u/Daneel)\
**Post date:** [October 9, 2020, 10:28am UTC](https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953/9 "2020-10-09T10:28:43Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [October 9, 2020, 10:37am UTC](https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953/10 "2020-10-09T10:37:39Z")

</div>

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 `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.

---

<div class="post-metadata">

**Author:** ![JesperMartinsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jespermartinsson/32/34098_2.png) [@JesperMartinsson](https://discourse.julialang.org/u/JesperMartinsson)\
**Post date:** [October 21, 2020, 8:19am UTC](https://discourse.julialang.org/t/pyplot-doesnt-release-mem-after-close/47953/11 "2020-10-21T08:19:01Z")

</div>

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).

```julia
using PyPlot
ioff()

for i = 1:2000
    println(i)
    figure()
    plot(randn(30000))
    savefig("figure_$i.png")
    close()
    GC.gc()
end

```
