Apparent memory leak in SDL_GL_SwapWindow on MacOS 11.3 Big Sur

I seem to be getting a memory leak in my SDL/OpenGL program on MacOS. I’ve tracked it down to the SDL_GL_SwapWindow call that I do every frame – looks like it’s allocating 104 bytes every single frame.

Here’s a screenshot from Instruments, which I’m using to tell where the memory leak is coming from:

As you can see, the stack trace comes from main, specifically the call to Cocoa_GL_SwapWindow. Then if you look at the table showing all the allocations, you can see by the timestamp that they are coming multiple times per millisecond, so it’s happening every frame.

SDL is big enough and I inexperienced enough that it seems pretty unlikely this is a problem with SDL2 and not with my own code … So what am I doing wrong??

Here’s the code where I can repro the problem:

#include <cstdio>
#include "SDL.h"

// openGL includes
#define GL_SILENCE_DEPRECATION // otherwise we get a ton of "opengl deprecated" warnings
#include "OpenGL/gl.h"
#define glGenVertexArrays glGenVertexArraysAPPLE
#define glBindVertexArray glBindVertexArrayAPPLE
#define glDeleteVertexArrays glDeleteVertexArraysAPPLE

SDL_Window *window = nullptr;
SDL_GLContext glContext = nullptr;
bool shouldQuit = false;

int main(int argc, char* argv[]) {
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);

    // not sure this is necessary
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);

    SDL_Init(SDL_INIT_VIDEO);

    window = SDL_CreateWindow(
            "SDL2 Test",
            SDL_WINDOWPOS_CENTERED,
            SDL_WINDOWPOS_CENTERED,
            640,
            480,
            SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL
    );
    if (window == nullptr) {
        printf("error creating window: %s", SDL_GetError());
        SDL_Quit();
        return 1;
    }

    glContext = SDL_GL_CreateContext(window);
    if (glContext == nullptr) {
        printf("error creating SDL_GLContext: %s", SDL_GetError());
        SDL_DestroyWindow(window);
        SDL_Quit();
        return 1;
    }
    SDL_GL_MakeCurrent(window, glContext);
    SDL_GL_SetSwapInterval(1); // enable vsync

    while (!shouldQuit) {
        //update
        SDL_Event e;
        while (SDL_PollEvent(&e)) {
            switch (e.type) {
            case SDL_QUIT:
                shouldQuit = true;
                break;
            case SDL_KEYDOWN:
                if (e.key.keysym.sym == SDLK_ESCAPE) {
                    shouldQuit = true;
                }
                break;
            }
        }

        // draw
        glClearColor(1.0f, 0, 0, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        SDL_GL_SwapWindow(window);
    }

    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

I’ve also put it up on GitHub if you want to take a look at the build script I’m using (CMake).

You appear to be inspecting allocations. Instruments is recording all allocations over the period of time you record. Freeing the allocated memory doesn’t remove the record of its allocation and its not supposed to. It is not indicative of a leak. Use the leak checker instrument to check for memory leaks instead.

Alright, good point. I took a look instrumenting leaks instead and it doesn’t seem to show any leaks.

However, memory usage is increasing steadily over the lifetime of the program. For a super simple program (just clears the screen), 158 MB is kind of a huge amount of memory. It doesn’t start out that high. As you can see on the graph below, it starts at almost half that amount, and then quickly increases over the first 20 seconds or so of the program’s lifetime. Then it seems to plateau a bit, however, it is still increasing.

The SDL_GL_SwapWindow still seems to be the best culprit. But, if nothing seems wrong in my repro program, maybe my best course of action is to dig into the profiler and see if I can eliminate freed allocations, and see what still remains.

I imagine OpenGL needs quite a bit of RAM, particularly if your monitor is 4k or more. I don’t find 160MB to be particularly alarming and 20 seconds is not enough time to measure to make any solid hypothesis.

The code for Cocoa_GL_SwapWindow is quite simple and does employ an @autoreleasepool. nothing on the SDL side of it is allocating anything directly.

Alright, that’s good to know. I just saw the quickly-increasing memory usage and got worried. I guess I’ll only have to worry about it if it eventually goes OOM and crashes. Thanks! :slight_smile: