Skip to main content
Known Participant
Nov 2, 2026 1:40 AM UTC
Open for Voting

Timer objects accumulate without limit, memory grows 0.25 GB / hour when idle

Description of Issue


- Lightroom's live AgTimerMac objects (AgSubstrate) keep accumulating: 226 just after launch, 224,705 after 34 minutes of culling, 950,048 after 8 more days idle in the background. Some are released (44,000 within 2 minutes of leaving Detail view), but far fewer than are created.


- Memory grows with them. Left open in the background with no interaction, the same process grew steadily by ~0.25 GB per hour (~6 GB per day) whenever the Mac was awake: 6 GB → 29 GB over 8 days, during 3½ of which the Mac was asleep.


- Most of the growth is small allocations made through the Lua VM. The churn also leaves the small-allocation zone heavily fragmented: 20.9 GB dirty against 8.1 GB of live allocations.


- For long stretches, the main thread runs a timer loop: an NSTimer fires, calls into Lua (AgSubstrate → lua_pcall), and the callback invalidates and re-creates a run-loop timer (CFRunLoopTimerInvalidate → __CFArmNextTimerInMode), ~6,400 times per second at a flat rate, independent of user input. The accumulating timer objects are consistent with this loop.

 

Step-by-step Reproduction Instructions


1. Quit Lightroom and launch it. To also record which code holds the memory, launch it with:
   open --env MallocStackLogging=lite -a "Adobe Lightroom"


2. Once startup and sync settle, note the memory and the timer count:
   footprint -p $(pgrep -x "Adobe Lightroom") | head -5
   heap $(pgrep -x "Adobe Lightroom") | grep AgTimerMac

 

3. Open a large raw shoot, cull in Detail view (D, arrow keys, Z / X) for 30 minutes, and repeat step 2.

 

4. Press G, switch to another app, leave Lightroom untouched in the background for 24 hours with the Mac awake, and repeat step 2. Also:
   vmmap --summary $(pgrep -x "Adobe Lightroom") | grep "Malloc Small"
   malloc_history $(pgrep -x "Adobe Lightroom") -callTree > tree.txt   (only with MallocStackLogging from step 1)

 

5. Optional, to see the timer loop (Xcode installed):
   xcrun xctrace record --template "System Trace" --attach $(pgrep -x "Adobe Lightroom") --time-limit 10s
   and count mk_timer_arm calls on the main thread.

 

The Expected Result


- Timer objects are released after they fire or are invalidated, so their count stays near its baseline


- An idle, backgrounded Lightroom's memory stays flat, and nothing re-arms a timer thousands of times per second

 

The Actual Result


- Live AgTimerMac objects (heap <pid>), one Lightroom process launched 2026-10-24 15:34:
  - 15:35, just after launch: 226 (footprint 2.7 GB)
  - 16:09, after 34 minutes of culling, still in Detail view: 224,705 (footprint 10 GB), ~6,700 more per minute
  - 16:11, two minutes later in Grid view: 180,528 (footprint 5.5 GB)
  - 2026-11-01 16:12, after 8 days idle in the background: 950,048 (32 MB of timer objects; footprint 27 GB), ~67 more per minute averaged over the 8 days, including the 3½ days the Mac was asleep

 

- Footprint while idle in the background, 2026-10-24 → 2026-11-01 (never brought to the front), sampled hourly:
  - Oct 24 16:35 → Oct 27 15:35, Mac awake: 6.2 → 24.2 GB, +18.0 GB over 71 hours (0.25 GB/hour, close to linear)
  - Oct 27 16:00 → Oct 31 13:24, Mac asleep (pmset -g log): no growth
  - Oct 31 → Nov 1 17:35, Mac awake again: +4.9 GB over 18 hours (0.27 GB/hour), ending at 29.5 GB
  The growth is in the Malloc Small zone: 2.3 GB → 25 GB dirty.

 

- Live heap 3.2 GB in 9.5 million allocations at the start of the idle period, 8.1 GB in 39.6 million allocations at the end:
  - 36.7 million allocations from the Lua allocator (AgKernel), 5.6 GB, average 153 bytes.
  - Allocation site WichitaFoundation+0x2c4324: 16 MB → 2,983 MB live.
  - Allocation site AgSubstrate+0x15c20: 158 MB → 1,052 MB live.

 

- vmmap, 2026-11-01: the Malloc Small zone holds 20.9 GB of dirty memory against 8.1 GB of live allocations, so ~13 GB is freed memory the allocator keeps but can't return to macOS. That fragmentation counts toward Lightroom's footprint.

 

- Timer loop: System Trace, 2026-10-19 23:17, 60 s: 1.14 million mk_timer_arm calls, ~99% on the main thread, from the NSTimer → Lua → CFRunLoopTimerInvalidate path above. Lightroom's Mach system calls (each timer re-arm is one) averaged ~18,800/s during a 10-minute browse on 2026-10-20 and ~10,900/s over a 35-minute culling session on 2026-10-24; with the loop not running it's ~1,000/s. On 2026-10-19 the loop ran for about an hour of mostly idle time, then stopped on its own without a restart.

 

- Notes: Lightroom was running with MallocStackLogging=lite (its own data was 257 MB and is excluded above). A monitoring tool queried Lightroom's Accessibility tree every 15 s during this period.

 

System Details


- Lightroom 9.6 (Mac App Store), build 20260923-1659-a32d844, arm64
- macOS 27.0.1 (26A434), MacBook Pro 16" (MacBookPro18,2), Apple M1 Max, 64 GB RAM
- Cameras: Canon R5m2 and R6m3
- Library: 41,490 photos, 211 albums, 4,818 stacks; local library 78–85 GB (40 GB originals, 29 GB proxies, 12 GB previews); all proxies stored locally, photo cache limit 50 GB
- Working set: an 11,650-photo Canon CR3 shoot