title: Why am I bleeding memory?
body: <p>heres a script to detect and record sound that ive been hacking on for a while. it works great, except that its memory usage grows after every successful detection. i fixed a similar issue that occurred during prolonged periods of silence (<code>if num_listening &gt; 4096:</code>...), but this one has me stumped.</p>
  <pre><code>
  from sys import byteorder
  from array import array
  from struct import pack
  from datetime import datetime
  
  import pyaudio
  import wave
  import os
  import time
  
  THRESHOLD = 6348
  MAX_SILENCE = 500
  CHUNK_SIZE = 1024
  FORMAT = pyaudio.paInt16
  RATE = 44100
  MAX_LENGTH = 1024
  
  def is_silent(snd_data):
      &quot;Returns 'True' if below the 'silent' threshold&quot;
      return max(snd_data) &lt; THRESHOLD
  
  def normalize(snd_data):
      &quot;Average the volume out&quot;
      MAXIMUM = 16384
      times = float(MAXIMUM)/max(abs(i) for i in snd_data)
  
      r = array('h')
      for i in snd_data:
          r.append(int(i*times))
      return r
  
  def trim(snd_data):
      &quot;Trim the blank spots at the start and end&quot;
      def _trim(snd_data):
          snd_started = False
          r = array('h')
  
          for i in snd_data:
              if not snd_started and abs(i) &gt; THRESHOLD:
                  snd_started = True
                  r.append(i)
  
              elif snd_started:
                  r.append(i)
          return r
  
      # Trim to the left
      snd_data = _trim(snd_data)
  
      # Trim to the right
      snd_data.reverse()
      snd_data = _trim(snd_data)
      snd_data.reverse()
      return snd_data
  
  def add_silence(snd_data, seconds):
      &quot;Add silence to the start and end of 'snd_data' of length 'seconds' (float)&quot;
      silence = [0] * int(seconds * RATE)
      r = array('h', silence)
      r.extend(snd_data)
      r.extend(silence)
      return r
  
  def record():
      &quot;&quot;&quot;
      Record a word or words from the microphone and 
      return the data as an array of signed shorts.
  
      Normalizes the audio, trims silence from the 
      start and end, and pads with 0.5 seconds of 
      blank sound to make sure VLC et al can play 
      it without getting chopped off.
      &quot;&quot;&quot;
      p = pyaudio.PyAudio()
      stream = p.open(format=FORMAT, channels=1, rate=RATE,
          input=True, output=True,
          frames_per_buffer=CHUNK_SIZE)
  
      num_silent = 0
      num_snd = 0
      num_listening = 0
      snd_started = False
  
      r = array('h')
  
      while num_snd &lt; MAX_LENGTH:
          # little endian, signed short
          snd_data = array('h', stream.read(CHUNK_SIZE, exception_on_overflow = False))
          if byteorder == 'big':
              snd_data.byteswap()
          r.extend(snd_data)
  
          silent = is_silent(snd_data)
  
          if not silent and not snd_started:
              snd_started = True
  
          if snd_started:
              num_snd += 1
              if num_silent &gt; MAX_SILENCE:
                  break
  
          if silent:
              if snd_started:
                  num_silent += 1
              if not snd_started:
                  num_listening += 1
                  if num_listening &gt; 4096:
                      del r[:]
                      num_listening = 0
  
      sample_width = p.get_sample_size(FORMAT)
      stream.stop_stream()
      stream.close()
      p.terminate()
  
      del r[0:8000]
  
      r = normalize(r)
      r = trim(r)
      r = add_silence(r, 0.5)
      return sample_width, r
  
  def record_to_file(path):
      &quot;Records from the microphone and outputs the resulting data to 'path'&quot;
      sample_width, data = record()
      data = pack('&lt;' + ('h'*len(data)), *data)
  
      wf = wave.open(path, 'wb')
      wf.setnchannels(1)
      wf.setsampwidth(sample_width)
      wf.setframerate(RATE)
      wf.writeframes(data)
      wf.close()
  
  if __name__ == '__main__':
      while True:
          print(&quot;Ready!&quot;)
          recorded = datetime.now()
          recorded = &quot;testpi1_&quot; + recorded.strftime(&quot;%Y-%m-%d--%H-%M-%S&quot;) + &quot;.wav&quot;
          record_to_file(&quot;/motion/&quot; + recorded)
          os.system(&quot;./convert-audio.py &quot; + recorded)
  </code></pre>