I created my own interface that just connected to this and launched multiple instances at the same time and with 12 instances at 32x speed there was a note-able memory leak that came from the audio when left running for a bit. This left hanging memory usage even when closed and took a very long time to clear out unless you restart the pc. Below is an explanation of it:
The audio memory leak was from the original program (modules/libmgba.py), not anything I added.
Here's what was happening in the original code: libmgba.py opens a sounddevice.RawOutputStream (PortAudio) for audio. At 32× speed, the emulator runs at ~1920 frames/second, and every single frame calls self._audio_stream.write(audio_data) — even when audio is disabled, because the stream was being used as a frame-rate throttle. That's ~2000 PortAudio write calls per second, per instance. PortAudio maintains internal C-level ring buffers and processing queues that accumulate memory at that rate and never get returned to the OS.
The manager I built was just launching the bot and displaying its output — it had no involvement with audio at all. The bot was simply never designed to be run at 32× speed for hours at a time; at normal 1× speed the audio write rate is 60/second which is fine.
The fix I made was to set POKEBOT_NO_AUDIO=1 in the launch environment, which prevents sounddevice from being imported in libmgba.py at all, so PortAudio never initializes. The throttling falls back to time.sleep() instead, which is slightly less precise but uses no C-level audio buffers
TLDR: My fix was completely dropping the audio.
I created my own interface that just connected to this and launched multiple instances at the same time and with 12 instances at 32x speed there was a note-able memory leak that came from the audio when left running for a bit. This left hanging memory usage even when closed and took a very long time to clear out unless you restart the pc. Below is an explanation of it:
The audio memory leak was from the original program (modules/libmgba.py), not anything I added.
Here's what was happening in the original code: libmgba.py opens a sounddevice.RawOutputStream (PortAudio) for audio. At 32× speed, the emulator runs at ~1920 frames/second, and every single frame calls self._audio_stream.write(audio_data) — even when audio is disabled, because the stream was being used as a frame-rate throttle. That's ~2000 PortAudio write calls per second, per instance. PortAudio maintains internal C-level ring buffers and processing queues that accumulate memory at that rate and never get returned to the OS.
The manager I built was just launching the bot and displaying its output — it had no involvement with audio at all. The bot was simply never designed to be run at 32× speed for hours at a time; at normal 1× speed the audio write rate is 60/second which is fine.
The fix I made was to set POKEBOT_NO_AUDIO=1 in the launch environment, which prevents sounddevice from being imported in libmgba.py at all, so PortAudio never initializes. The throttling falls back to time.sleep() instead, which is slightly less precise but uses no C-level audio buffers
TLDR: My fix was completely dropping the audio.