Memory limits

В рендеринг-контексте Mapbox GL JS ключевым фактором стабильности выступает управление памятью на нескольких уровнях: браузерный heap, WebGL-графическая память, кэш тайлов и вспомогательные структуры (шрифты, спрайты, worker-потоки). Ограничения проявляются особенно явно на мобильных устройствах и слабых GPU, где перерасход ресурсов приводит к деградации производительности, пропуску кадров или сбросу WebGL-контекста.


Общая модель потребления памяти

Архитектура рендеринга Mapbox GL JS распределяет нагрузку между CPU и GPU:

  • CPU-слой: загрузка тайлов, декодирование vector tiles, управление стилем
  • GPU-слой: отрисовка геометрии, текстурирование, обработка шейдеров
  • Web Worker слой: параллельная обработка тайлов и геометрии

Каждый слой формирует собственный профиль потребления памяти. При этом GPU-память часто становится лимитирующим фактором раньше, чем JavaScript heap.


Кэш тайлов и стратегия вытеснения

Кэш тайлов является центральным элементом работы карты. Он хранит:

  • векторные тайлы после декодирования
  • растровые тайлы с текстурами
  • промежуточные геометрические буферы
  • результаты layout-процедур

Внутренний механизм кэширования реализует LRU-подобную стратегию (Least Recently Used). При превышении бюджета памяти происходит вытеснение наименее используемых тайлов.

Основные параметры влияния:

  • размер viewport и количество одновременно видимых тайлов
  • zoom level (чем выше zoom, тем больше уникальных тайлов)
  • количество активных слоев
  • плотность данных (особенно в vector tiles)

В условиях сложных стилей кэш быстро заполняется, особенно при наличии большого количества символов и подписей.


Ограничения WebGL и графическая память

GPU-память в Mapbox GL JS используется для:

  • vertex buffers (геометрия)
  • index buffers
  • texture atlases (спрайты и glyphs)
  • framebuffers (offscreen rendering)
  • depth/stencil buffers

Основные источники переполнения:

Геометрические буферы

Сложные полигоны и линии с высокой детализацией увеличивают объем vertex buffer. При использовании line-join: round или line-cap: round количество вершин возрастает экспоненциально.

Текстуры

Текстуры создаются для:

  • растровых тайлов
  • спрайтов и иконок
  • шрифтовых глифов

Каждая текстура занимает память кратно степени 2 (2^n), что приводит к внутренней фрагментации GPU-памяти.


Шрифты и glyph cache

Glyph cache является одной из наиболее чувствительных подсистем.

При использовании большого количества языков или кастомных шрифтов:

  • увеличивается количество запросов glyph ranges
  • растёт atlas size
  • возрастает время компоновки текста

Шрифты разбиваются на диапазоны Unicode, которые загружаются лениво. Однако при насыщенных подписях (особенно на высоких zoom уровнях) кэш glyphs может занять значительную часть GPU памяти.

Дополнительная нагрузка возникает при:

  • динамических стилях текста
  • частом изменении text-field
  • использовании выражений (expressions) для текста

Sprite atlas и иконки

Sprite atlas объединяет множество иконок в одну текстуру. Несмотря на оптимизацию, есть несколько ограничений:

  • максимальный размер текстуры зависит от GPU (часто 2048x2048 или 4096x4096)
  • увеличение числа иконок приводит к росту atlas и фрагментации
  • повторная упаковка sprite atlas может быть дорогостоящей операцией

При больших стилях с сотнями иконок происходит:

  • рост времени загрузки стиля
  • увеличение памяти GPU
  • замедление переключения стилей

Векторные тайлы и декодирование

Векторные тайлы занимают память не только в сжатом виде, но и после декодирования:

  • геометрия распаковывается в промежуточные структуры
  • свойства feature сохраняются в JS объектах
  • выполняется сортировка по слоям и фильтрам

Особенно затратными являются:

  • сложные GeoJSON-конверсии
  • большие наборы точек (POI datasets)
  • dense road networks

Декодирование происходит в Web Workers, однако итоговые структуры попадают в главный поток для рендеринга, что увеличивает pressure на JavaScript heap.


3D-слои и fill-extrusion

Использование 3D-экструзий увеличивает нагрузку на GPU:

  • дополнительные вершины для боковых граней
  • увеличенные vertex attributes
  • необходимость глубинного буфера

Особенности:

  • fill-extrusion layers масштабируются с zoom, создавая дополнительные пересчёты
  • пересечение объектов требует дополнительной обработки depth testing
  • увеличивается размер render passes

На слабых GPU 3D-режим может приводить к резкому падению FPS из-за переполнения fill rate.


Worker-память и параллельная обработка

Mapbox GL JS активно использует Web Workers для:

  • декодирования vector tiles
  • вычисления layout для текста
  • генерации геометрии

Каждый worker имеет собственный heap, что приводит к:

  • дублированию некоторых данных между потоками
  • дополнительным накладным расходам на передачу сообщений (structured cloning)
  • росту общего memory footprint

При большом количестве worker threads увеличивается давление на системную память, особенно на устройствах с ограниченным RAM.


Ограничения tile cache и внутренние бюджеты

Внутренний tile cache управляется через бюджет памяти. При превышении лимита происходит:

  • удаление неиспользуемых тайлов
  • пересоздание геометрии при возврате в область видимости
  • повторная загрузка данных с сети или локального кэша браузера

Факторы, влияющие на потребление:

  • плотность тайлов в viewport
  • активные фильтры style layers
  • использование heatmap и clustering
  • частота pan/zoom операций

Высокая интерактивность приводит к постоянной инвалидации кэша.


Типичные сценарии переполнения памяти

Перегруженные символические слои

Большое количество label layers с динамическими выражениями приводит к росту glyph cache и layout recomputation.

Данные высокой плотности

Наборы точек (десятки миллионов features) создают чрезмерную нагрузку на CPU и GPU одновременно.

Частые смены стилей

Переключение стилей приводит к:

  • сбросу всех текстур
  • очистке tile cache
  • повторной загрузке ресурсов

Длинные маршруты и линии

Линии с высокой детализацией увеличивают vertex buffers и могут превышать лимиты attribute buffers GPU.


Профилирование и диагностика

Мониторинг памяти в контексте Mapbox GL JS включает несколько уровней:

  • WebGL memory (через инструменты браузера)
  • JS heap snapshots
  • performance metrics (FPS, render time)
  • tile cache statistics

Внутренние метрики рендеринга позволяют выявлять:

  • количество активных tiles
  • размер sprite atlas
  • glyph cache usage
  • number of draw calls

Браузерные DevTools фиксируют:

  • GPU process memory
  • detached canvas leaks
  • texture allocations

Ограничения на уровне браузера

Браузер накладывает дополнительные лимиты:

  • максимальный размер WebGL texture
  • ограничение на количество uniform variables
  • лимит buffer objects
  • квоты на GPU process memory

При достижении лимитов возможны:

  • fallback на software rendering
  • потеря WebGL context
  • автоматический reset canvas

Оптимизационные стратегии

В контексте Mapbox практики оптимизации направлены на снижение нагрузки на GPU и сокращение tile churn:

  • сокращение количества style layers
  • использование растровых тайлов вместо векторных в низкоинтерактивных сценах
  • ограничение maxzoom и minzoom
  • упрощение геометрии (geometry simplification)
  • уменьшение количества glyph ranges
  • агрегация точек (clustering)
  • снижение частоты перерисовки через throttling событий камеры

Дополнительно используется:

  • уменьшение количества уникальных иконок
  • переиспользование sprite atlas
  • оптимизация expression-heavy слоёв
  • отключение 3D в низкопроизводительных режимах

Поведение при критических ограничениях

При достижении пределов памяти система рендеринга переходит в деградированный режим:

  • снижение детализации тайлов
  • упрощение геометрии
  • пропуск необязательных слоёв
  • уменьшение частоты обновления текста

В крайних случаях происходит потеря WebGL-контекста, после чего требуется полная инициализация рендера и повторная загрузка графических ресурсов.