Commit e7347a4027b8d3e156ec367cb9623571a3066b0e

Ryan C. Gordon 2016-08-06T02:27:55

audio: SDL_ClearQueuedAudio() should free everything but two packets. Otherwise, if you had a massive, one-time queue buildup, the memory from that remains allocated until you close the device. Also, if you are just using a reasonable amount of space, this would previously cause you to reallocate it over and over instead of keeping a little bit of memory around.

diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 4c43693..ec3817b 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -586,20 +586,44 @@ void
 SDL_ClearQueuedAudio(SDL_AudioDeviceID devid)
 {
     SDL_AudioDevice *device = get_audio_device(devid);
-    SDL_AudioBufferQueue *buffer = NULL;
+    SDL_AudioBufferQueue *packet;
+
     if (!device) {
         return;  /* nothing to do. */
     }
 
     /* Blank out the device and release the mutex. Free it afterwards. */
     current_audio.impl.LockDevice(device);
-    buffer = device->buffer_queue_head;
+
+    /* merge the available pool and the current queue into one list. */
+    packet = device->buffer_queue_head;
+    if (packet) {
+        device->buffer_queue_tail->next = device->buffer_queue_pool;
+    } else {
+        packet = device->buffer_queue_pool;
+    }
+
+    /* Remove the queued packets from the device. */
     device->buffer_queue_tail = NULL;
     device->buffer_queue_head = NULL;
     device->queued_bytes = 0;
+    device->buffer_queue_pool = packet;
+
+    /* Keep up to two packets in the pool to reduce future malloc pressure. */
+    if (packet) {
+        if (!packet->next) {
+            packet = NULL;  /* one packet (the only one) for the pool. */
+        } else {
+            SDL_AudioBufferQueue *next = packet->next->next;
+            packet->next->next = NULL;  /* two packets for the pool. */
+            packet = next;  /* rest will be freed. */
+        }
+    }
+
     current_audio.impl.UnlockDevice(device);
 
-    free_audio_queue(buffer);
+    /* free any extra packets we didn't keep in the pool. */
+    free_audio_queue(packet);
 }