On macOS, the reviewer webview leaks graphics memory continuously — roughly 70 MB/min on this machine — for as long as a card containing an animated GIF is displayed. No interaction is needed; the process footprint grows until the system starts compressing/swapping (observed past 5.5 GB on an 8 GB machine), and quitting Anki then hangs for over a minute tearing down the graphics context.
The trigger is not GIFs specifically but repaint rate: the same content repainting at ~30 fps leaks at the same rate, while repainting at 20 fps or less measures flat. Details and data below.
Reproduced with the add-on that first exposed it disabled; a plain Basic card is sufficient
Minimal reproduction
Create a Basic card whose Front contains one animated GIF (ours: 480x480, 2.4 MB, 599 frames, 30 ms/frame — but a small ~100 KB GIF leaks at the same rate).
Review the card and leave it on screen. The Anki window must be visible on the active desktop — an occluded window (other Space, minimized) throttles rendering and the leak pauses, which can hide the problem during testing.
Sample footprint -p <anki pid> every 15 s for 4 minutes and fit a slope. (Use footprint, not ps RSS — RSS reads ~130 MB while the true footprint is gigabytes once macOS starts compressing the process.)
Measured: +69.8 MB/min, linear, zero interaction. With a static image instead: ~0 MB/min. The rate looks independent of GIF file size and pixel area, consistent with a fixed per-repaint loss.
The repaint-rate threshold
To separate GIF decoding from repainting, we replaced the GIF with JavaScript that decodes the frames once (WebCodecs ImageDecoder) and draws them onto a <canvas> in a setTimeout loop, then varied only the draw interval. Same content, window visible throughout:
Repaint interval
Rate
Footprint slope
native GIF playback (30-40 ms frames)
~30 fps
+68 to +70 MB/min
canvas, 30-40 ms
~30 fps
+70.4 MB/min
canvas, >= 50 ms
<= 20 fps
+6.2 MB/min (flat)
canvas, 100 ms
10 fps
-15.5 MB/min (flat)
static content
0
~0 MB/min
So the leak sits in the compositing path, engaged above some repaint rate between 20 and 30 fps on this machine — not in the GIF decoder.
Where the memory goes
vmmap at a 5156 MB footprint: MALLOC_SMALL 3719 MB across 1003 regions, IOSurface 555 MB, IOAccelerator (GPU) 369 MB, graphics-unmapped 105 MB.
Related symptom: quit hang
After the footprint has grown, quitting Anki hangs. macOS wrote a hang report (81.94 s, footprint 5484 MB) with all 128 samples of the main thread inside -[NSOpenGLContext dealloc] → CGLReleaseContext → gliDestroyContext — i.e. teardown of the accumulated graphics state. The longer a session with an animated GIF, the longer the quit hang.
Notes
Raw sample TSVs (timestamp, footprint MB) for every run are available, as is the full hang report.
Workaround we ship in the triggering add-on: animate via canvas capped at >= 50 ms/frame — flat memory even during active reviewing (+9.7 MB/min while answering cards, within measurement noise).
Happy to run diagnostics or test builds on this machine.
I was not able to reproduce the reported behavior.
M1 Mac mini 2020, macOS Tahoe 26.6.1, Anki 26.08.1, Video driver: Metal (default).
Using the animated GIF on this page. 320 x 240 px, 41 frames, 0.08 delay time, 0.08 unclamped delay time.
I reviewed the card, leaving it in the window in the unanswered state (with the “Show Answer” button at the bottom).
First test:
(I didn’t keep strict track of time during the early part of testing.)
Before testing, the footprint was 214 MB.
After starting testing, the footprint jumped to 243 MB.
Within a minute, it dropped to 238 MB.
A few minutes later, it dropped to 209 MB.
A few minutes later: 208 MB.
At that point, I started keeping track of timestamps.
2 minutes later: 209 MB.
1 minute later: 212 MB.
45 seconds later: 210 MB.
For the next 5 minutes, it fluctuated between 209-210 MB.
6 minutes later, it jumped to 237 MB.
For the next 10 minutes, it fluctuated between 236-237 MB.
3 minutes later: 237 MB.
3 minutes later: 237 MB.
13 minutes later, 237 MB.
Second test:
Before pressing “Study Now” to view the card: 160 MB
Immediately after pressing “Study Now” and viewing the card: 193 MB
2 minutes later: 189 MB
5 minutes later: 192 MB
5 minutes later: 192 MB
9 minutes later: 191 MB