Джанк скролла только на старых устройствах и только после 5 минут — воспроизведите, измерьте, найдите причину
Пользователи сообщают о джанке скролла, что виден лишь на старых устройствах и лишь после ~5 минут использования. На новейшем устройстве всё гладко. Ниже два захвата на старом устройстве: холодный запуск и после пяти минут просмотра.
Fresh After 5 min
Frame rate (scroll) 60 fps 38 fps
Resident memory 190 MB 540 MB
Main-thread self 8 ms/frame 22 ms/frame
Top self symbol render ImageCache.subscript
Объясните, как вы воспроизводите, измеряете и находите причину.
Воспроизводите на старом устройстве и гоняйте пять минут — важно накопленное состояние, а не холодный запуск. Мерьте Time Profiler и Allocations вместе. Память растёт до 540 МБ, наверху ImageCache — безграничный кэш даёт давление. Ограничьте кэш.
- ✗Профилируют холодный запуск на новом устройстве вместо состарившегося состояния на старом
- ✗Отмахиваются от зависящего от времени джанка как невоспроизводимого
- ✗Игнорируют рост памяти как причину джанка скролла
- →Почему давление памяти проявляется как джанк скролла, а не сперва как крах?
- →Как подтвердить, что рост — это кэш картинок, а не утечка?
The bug is time- and device-dependent, so the setup is the whole game: profile on the oldest supported device (its smaller memory and slower CPU are the trigger) and drive it for five minutes to reach the janky state — a cold launch never reproduces it. Run Time Profiler and Allocations together so you correlate frame cost with memory over the session:
Fresh After 5 min delta
Resident memory 190 MB 540 MB +350 MB, monotonic
Main self/frame 8 ms 22 ms work per frame nearly tripled
Top self symbol render ImageCache the cache now dominates
The signature — memory climbing monotonically and per-frame work rising with it, ImageCache on top — is an unbounded cache. As it grows the device hits memory pressure, the allocator and decode paths do more work per frame, and scrolling drops frames. Confirm with Allocations generational marks (growth is retained, not leaked), then bound the cache with an NSCache count/cost limit or eviction. Smoothness returns and memory plateaus.