<h3 dir="auto">Bug report</h3>
<p dir="auto">When plotting and saving a lot of spectrograms in a loop, there seems to be a memory leek. I'm aware that this is some kind of  a common problem and I tried already all kind of combinations of plotting the figure new every step, reusing the figure, using plt.close(), plt.close('fig'), gc.collect(), plt.clf(), plt.cla(), but nothing really worked.<br>
Interestingly, I could pinpoint that the leak does not appear or at least gets negligible when the yscale is not 'log'. Can someone give me a work around or has an idea how to set the axis to log without suffering the memory leak?</p>
<p dir="auto"><strong>Code for reproduction</strong></p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import gc
import psutil
import os
import matplotlib.pyplot as plt
import numpy as np

process = psutil.Process(os.getpid())
# initial memory usage
bytes_used_start = process.memory_info().rss

# generate 10 min data
fs = 20000
x = np.random.rand(fs*600)

for i in range(10):
    
    # create figure
    fig = plt.figure(figsize=(10,6))    
    ax = fig.add_axes([0, 0, 1, 1])   
    
    # plot spectrogram
    spectro, freqs, t, im = ax.specgram(
            x=x,
            NFFT=2**13,
            Fs=fs
            )
    
    ax.axes.set_ylim((9.8,10000))
    #ax.axes.set_yscale('log')      # -&gt; comment this line in for memory leak
    
    fig.savefig('C:/Temp/spectro_{}.jpg'.format(i))
        
    # clean up
    plt.close(fig)
    gc.collect()
    
    # show memory usage
    bytes_used_cur =  process.memory_info().rss - bytes_used_start
    print('bytes used currently at step {} : {}'.format(i, bytes_used_cur))"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">gc</span>
<span class="pl-k">import</span> <span class="pl-s1">psutil</span>
<span class="pl-k">import</span> <span class="pl-s1">os</span>
<span class="pl-k">import</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">pyplot</span> <span class="pl-k">as</span> <span class="pl-s1">plt</span>
<span class="pl-k">import</span> <span class="pl-s1">numpy</span> <span class="pl-k">as</span> <span class="pl-s1">np</span>

<span class="pl-s1">process</span> <span class="pl-c1">=</span> <span class="pl-s1">psutil</span>.<span class="pl-v">Process</span>(<span class="pl-s1">os</span>.<span class="pl-en">getpid</span>())
<span class="pl-c"># initial memory usage</span>
<span class="pl-s1">bytes_used_start</span> <span class="pl-c1">=</span> <span class="pl-s1">process</span>.<span class="pl-en">memory_info</span>().<span class="pl-s1">rss</span>

<span class="pl-c"># generate 10 min data</span>
<span class="pl-s1">fs</span> <span class="pl-c1">=</span> <span class="pl-c1">20000</span>
<span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-s1">random</span>.<span class="pl-en">rand</span>(<span class="pl-s1">fs</span><span class="pl-c1">*</span><span class="pl-c1">600</span>)

<span class="pl-k">for</span> <span class="pl-s1">i</span> <span class="pl-c1">in</span> <span class="pl-en">range</span>(<span class="pl-c1">10</span>):
    
    <span class="pl-c"># create figure</span>
    <span class="pl-s1">fig</span> <span class="pl-c1">=</span> <span class="pl-s1">plt</span>.<span class="pl-en">figure</span>(<span class="pl-s1">figsize</span><span class="pl-c1">=</span>(<span class="pl-c1">10</span>,<span class="pl-c1">6</span>))    
    <span class="pl-s1">ax</span> <span class="pl-c1">=</span> <span class="pl-s1">fig</span>.<span class="pl-en">add_axes</span>([<span class="pl-c1">0</span>, <span class="pl-c1">0</span>, <span class="pl-c1">1</span>, <span class="pl-c1">1</span>])   
    
    <span class="pl-c"># plot spectrogram</span>
    <span class="pl-s1">spectro</span>, <span class="pl-s1">freqs</span>, <span class="pl-s1">t</span>, <span class="pl-s1">im</span> <span class="pl-c1">=</span> <span class="pl-s1">ax</span>.<span class="pl-en">specgram</span>(
            <span class="pl-s1">x</span><span class="pl-c1">=</span><span class="pl-s1">x</span>,
            <span class="pl-v">NFFT</span><span class="pl-c1">=</span><span class="pl-c1">2</span><span class="pl-c1">**</span><span class="pl-c1">13</span>,
            <span class="pl-v">Fs</span><span class="pl-c1">=</span><span class="pl-s1">fs</span>
            )
    
    <span class="pl-s1">ax</span>.<span class="pl-s1">axes</span>.<span class="pl-en">set_ylim</span>((<span class="pl-c1">9.8</span>,<span class="pl-c1">10000</span>))
    <span class="pl-c">#ax.axes.set_yscale('log')      # -&gt; comment this line in for memory leak</span>
    
    <span class="pl-s1">fig</span>.<span class="pl-en">savefig</span>(<span class="pl-s">'C:/Temp/spectro_{}.jpg'</span>.<span class="pl-en">format</span>(<span class="pl-s1">i</span>))
        
    <span class="pl-c"># clean up</span>
    <span class="pl-s1">plt</span>.<span class="pl-en">close</span>(<span class="pl-s1">fig</span>)
    <span class="pl-s1">gc</span>.<span class="pl-en">collect</span>()
    
    <span class="pl-c"># show memory usage</span>
    <span class="pl-s1">bytes_used_cur</span> <span class="pl-c1">=</span>  <span class="pl-s1">process</span>.<span class="pl-en">memory_info</span>().<span class="pl-s1">rss</span> <span class="pl-c1">-</span> <span class="pl-s1">bytes_used_start</span>
    <span class="pl-en">print</span>(<span class="pl-s">'bytes used currently at step {} : {}'</span>.<span class="pl-en">format</span>(<span class="pl-s1">i</span>, <span class="pl-s1">bytes_used_cur</span>))</pre></div>
<p dir="auto"><strong>Outcome yscale linear</strong></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="bytes used currently at step 0 : 256192512
bytes used currently at step 1 : 257204224
bytes used currently at step 2 : 257437696
bytes used currently at step 3 : 257343488
bytes used currently at step 4 : 257519616
bytes used currently at step 5 : 257581056
bytes used currently at step 6 : 257515520
bytes used currently at step 7 : 257581056
bytes used currently at step 8 : 257449984
bytes used currently at step 9 : 257585152"><pre class="notranslate"><code class="notranslate">bytes used currently at step 0 : 256192512
bytes used currently at step 1 : 257204224
bytes used currently at step 2 : 257437696
bytes used currently at step 3 : 257343488
bytes used currently at step 4 : 257519616
bytes used currently at step 5 : 257581056
bytes used currently at step 6 : 257515520
bytes used currently at step 7 : 257581056
bytes used currently at step 8 : 257449984
bytes used currently at step 9 : 257585152
</code></pre></div>
<p dir="auto"><strong>Outcome yscale log</strong></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="bytes used currently at step 0 : 42557440
bytes used currently at step 1 : 83501056
bytes used currently at step 2 : 122126336
bytes used currently at step 3 : 161177600
bytes used currently at step 4 : 199602176
bytes used currently at step 5 : 238022656
bytes used currently at step 6 : 276516864
bytes used currently at step 7 : 314994688
bytes used currently at step 8 : 353480704
bytes used currently at step 9 : 391954432"><pre class="notranslate"><code class="notranslate">bytes used currently at step 0 : 42557440
bytes used currently at step 1 : 83501056
bytes used currently at step 2 : 122126336
bytes used currently at step 3 : 161177600
bytes used currently at step 4 : 199602176
bytes used currently at step 5 : 238022656
bytes used currently at step 6 : 276516864
bytes used currently at step 7 : 314994688
bytes used currently at step 8 : 353480704
bytes used currently at step 9 : 391954432
</code></pre></div>
<p dir="auto"><strong>Matplotlib version</strong></p>

<ul dir="auto">
<li>Operating system: Windows 7</li>
<li>Matplotlib version: '3.1.3'</li>
<li>Matplotlib backend: Qt5Agg</li>
<li>Python version: 3.7.4</li>
</ul>
<p dir="auto">matplotlib seems to leak memory when I switch to log scale on the Y axis, for the functions <code class="notranslate">pcolorfast</code>, <code class="notranslate">pcolormesh</code>, <code class="notranslate">imshow</code> and <code class="notranslate">specgram</code></p>
<p dir="auto">Please consider the following spectrogram animation (sorry for the extra dependencies to <code class="notranslate">scipy</code>)</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from scipy.signal.spectral import spectrogram
from scipy.signal.waveforms import chirp

import matplotlib.animation as animation
import matplotlib.pyplot as plt
import numpy as np

fs = 8000 # sampling rate
t = np.arange(0, 5.0, 1/fs) # 5 seconds of time

fig, axes = plt.subplots(nrows=1)

def signal(t): # generates a &quot;chirp&quot; signal
    return chirp(t = t, f0 = 100.0,  f1 = 3000.0, t1 = 10.0)

def spect(x): # computes spectrogram
    freq, time, Sxx = spectrogram(x, fs = fs, nfft = 1024, noverlap = 512, nperseg = 1024)
    Z = 10 * np.log10(Sxx)
    return freq, time, Z

y = signal(t)
freq, time, Z = spect(y)
im = axes.pcolorfast(time, freq, Z)
axes.set_xlabel('t [s]')
axes.set_ylabel('f [Hz]')
axes.set_yscale('log') # &lt;-- exposes the leak
axes.set_ylim(0, fs/2)

def animate(i):
    y = signal(t + i/30.0) # sliding temporal window
    freq, time, Z = spect(y)
    im.set_data(Z)
    return [ im ]

ani = animation.FuncAnimation(fig, animate, np.arange(1, 200), 
                              interval=0, blit=True)
plt.show()"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">scipy</span>.<span class="pl-s1">signal</span>.<span class="pl-s1">spectral</span> <span class="pl-k">import</span> <span class="pl-s1">spectrogram</span>
<span class="pl-k">from</span> <span class="pl-s1">scipy</span>.<span class="pl-s1">signal</span>.<span class="pl-s1">waveforms</span> <span class="pl-k">import</span> <span class="pl-s1">chirp</span>

<span class="pl-k">import</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">animation</span> <span class="pl-k">as</span> <span class="pl-s1">animation</span>
<span class="pl-k">import</span> <span class="pl-s1">matplotlib</span>.<span class="pl-s1">pyplot</span> <span class="pl-k">as</span> <span class="pl-s1">plt</span>
<span class="pl-k">import</span> <span class="pl-s1">numpy</span> <span class="pl-k">as</span> <span class="pl-s1">np</span>

<span class="pl-s1">fs</span> <span class="pl-c1">=</span> <span class="pl-c1">8000</span> <span class="pl-c"># sampling rate</span>
<span class="pl-s1">t</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">arange</span>(<span class="pl-c1">0</span>, <span class="pl-c1">5.0</span>, <span class="pl-c1">1</span><span class="pl-c1">/</span><span class="pl-s1">fs</span>) <span class="pl-c"># 5 seconds of time</span>

<span class="pl-s1">fig</span>, <span class="pl-s1">axes</span> <span class="pl-c1">=</span> <span class="pl-s1">plt</span>.<span class="pl-en">subplots</span>(<span class="pl-s1">nrows</span><span class="pl-c1">=</span><span class="pl-c1">1</span>)

<span class="pl-k">def</span> <span class="pl-en">signal</span>(<span class="pl-s1">t</span>): <span class="pl-c"># generates a "chirp" signal</span>
    <span class="pl-k">return</span> <span class="pl-en">chirp</span>(<span class="pl-s1">t</span> <span class="pl-c1">=</span> <span class="pl-s1">t</span>, <span class="pl-s1">f0</span> <span class="pl-c1">=</span> <span class="pl-c1">100.0</span>,  <span class="pl-s1">f1</span> <span class="pl-c1">=</span> <span class="pl-c1">3000.0</span>, <span class="pl-s1">t1</span> <span class="pl-c1">=</span> <span class="pl-c1">10.0</span>)

<span class="pl-k">def</span> <span class="pl-en">spect</span>(<span class="pl-s1">x</span>): <span class="pl-c"># computes spectrogram</span>
    <span class="pl-s1">freq</span>, <span class="pl-s1">time</span>, <span class="pl-v">Sxx</span> <span class="pl-c1">=</span> <span class="pl-en">spectrogram</span>(<span class="pl-s1">x</span>, <span class="pl-s1">fs</span> <span class="pl-c1">=</span> <span class="pl-s1">fs</span>, <span class="pl-s1">nfft</span> <span class="pl-c1">=</span> <span class="pl-c1">1024</span>, <span class="pl-s1">noverlap</span> <span class="pl-c1">=</span> <span class="pl-c1">512</span>, <span class="pl-s1">nperseg</span> <span class="pl-c1">=</span> <span class="pl-c1">1024</span>)
    <span class="pl-v">Z</span> <span class="pl-c1">=</span> <span class="pl-c1">10</span> <span class="pl-c1">*</span> <span class="pl-s1">np</span>.<span class="pl-en">log10</span>(<span class="pl-v">Sxx</span>)
    <span class="pl-k">return</span> <span class="pl-s1">freq</span>, <span class="pl-s1">time</span>, <span class="pl-v">Z</span>

<span class="pl-s1">y</span> <span class="pl-c1">=</span> <span class="pl-en">signal</span>(<span class="pl-s1">t</span>)
<span class="pl-s1">freq</span>, <span class="pl-s1">time</span>, <span class="pl-v">Z</span> <span class="pl-c1">=</span> <span class="pl-en">spect</span>(<span class="pl-s1">y</span>)
<span class="pl-s1">im</span> <span class="pl-c1">=</span> <span class="pl-s1">axes</span>.<span class="pl-en">pcolorfast</span>(<span class="pl-s1">time</span>, <span class="pl-s1">freq</span>, <span class="pl-v">Z</span>)
<span class="pl-s1">axes</span>.<span class="pl-en">set_xlabel</span>(<span class="pl-s">'t [s]'</span>)
<span class="pl-s1">axes</span>.<span class="pl-en">set_ylabel</span>(<span class="pl-s">'f [Hz]'</span>)
<span class="pl-s1">axes</span>.<span class="pl-en">set_yscale</span>(<span class="pl-s">'log'</span>) <span class="pl-c"># &lt;-- exposes the leak</span>
<span class="pl-s1">axes</span>.<span class="pl-en">set_ylim</span>(<span class="pl-c1">0</span>, <span class="pl-s1">fs</span><span class="pl-c1">/</span><span class="pl-c1">2</span>)

<span class="pl-k">def</span> <span class="pl-en">animate</span>(<span class="pl-s1">i</span>):
    <span class="pl-s1">y</span> <span class="pl-c1">=</span> <span class="pl-en">signal</span>(<span class="pl-s1">t</span> <span class="pl-c1">+</span> <span class="pl-s1">i</span><span class="pl-c1">/</span><span class="pl-c1">30.0</span>) <span class="pl-c"># sliding temporal window</span>
    <span class="pl-s1">freq</span>, <span class="pl-s1">time</span>, <span class="pl-v">Z</span> <span class="pl-c1">=</span> <span class="pl-en">spect</span>(<span class="pl-s1">y</span>)
    <span class="pl-s1">im</span>.<span class="pl-en">set_data</span>(<span class="pl-v">Z</span>)
    <span class="pl-k">return</span> [ <span class="pl-s1">im</span> ]

<span class="pl-s1">ani</span> <span class="pl-c1">=</span> <span class="pl-s1">animation</span>.<span class="pl-v">FuncAnimation</span>(<span class="pl-s1">fig</span>, <span class="pl-s1">animate</span>, <span class="pl-s1">np</span>.<span class="pl-en">arange</span>(<span class="pl-c1">1</span>, <span class="pl-c1">200</span>), 
                              <span class="pl-s1">interval</span><span class="pl-c1">=</span><span class="pl-c1">0</span>, <span class="pl-s1">blit</span><span class="pl-c1">=</span><span class="pl-c1">True</span>)
<span class="pl-s1">plt</span>.<span class="pl-en">show</span>()</pre></div>
<p dir="auto">Everything stays stable if I stick to linear scale on the Y axis, commenting out the line</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="axes.set_yscale('log')"><pre class="notranslate"><span class="pl-s1">axes</span>.<span class="pl-en">set_yscale</span>(<span class="pl-s">'log'</span>)</pre></div>
<p dir="auto">I can reproduce it with matplotlib <code class="notranslate">3.1.1</code> (via <code class="notranslate">pip</code>) and previous versions (tested with <code class="notranslate">3.0.2</code> from system-wide Debian testing package). Also I am using <code class="notranslate">Qt5Agg</code> backend and <code class="notranslate">python 3.7.5rc1</code></p>