Уничтожение текстур и освобождение памяти

В PixiJS управление ресурсами играет ключевую роль в поддержании производительности и предотвращении утечек памяти. Особенно важно правильно уничтожать текстуры и связанные с ними объекты после того, как они перестали быть нужны, поскольку графические ресурсы занимают значительное место в GPU и оперативной памяти.


Основные понятия

Текстура (Texture) в PixiJS — это объект, представляющий изображение, которое может быть отрисовано с помощью спрайта (Sprite) или другого графического объекта. При загрузке изображений через PIXI.Loader создаются текстуры, которые остаются в памяти, даже если все спрайты, их использующие, удалены.

Спрайт (Sprite) — это объект визуального представления текстуры на сцене. Уничтожение спрайта не автоматически очищает текстуру, на которой он основан.


Методы уничтожения текстур

destroy(options)

Метод destroy применяется как к текстурам, так и к спрайтам. Для текстур ключевое значение имеют следующие опции:

texture.destroy({ baseTexture: true });
  • baseTexture: если true, уничтожается базовая текстура (BaseTexture), освобождая GPU-память.
  • destroyBase: устаревший вариант опции, аналогичен baseTexture.

Пример правильного уничтожения текстуры

const texture = PIXI.Texture.from('image.png');
const sprite = new PIXI.Sprite(texture);

// После использования
sprite.destroy(); // удаляет спрайт, но текстура остаётся
texture.destroy(true); // уничтожает текстуру и базовую текстуру

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


Использование BaseTexture

Каждая текстура содержит ссылку на BaseTexture, который хранит данные изображения и управляет ресурсами GPU. Уничтожение текстуры без очистки BaseTexture освободит объект в JS, но текстура в GPU останется, что приведет к росту потребления видеопамяти.

texture.baseTexture.destroy();

Использование baseTexture.destroy() напрямую — более низкоуровневый способ, который освобождает GPU-ресурсы без уничтожения объекта Texture в JS.


Очистка ресурсов при загрузке через Loader

Loader автоматически создаёт текстуры для загруженных ресурсов. После завершения сцены или уровня необходимо освобождать их:

PIXI.Loader.shared.add('sprite', 'sprite.png').load((loader, resources) => {
    const sprite = new PIXI.Sprite(resources.sprite.texture);

    // ... использование sprite

    // Уничтожение после использования
    sprite.destroy();
    resources.sprite.texture.destroy(true); // освобождение BaseTexture
});

Для больших проектов рекомендуется хранить список всех используемых текстур и освобождать их централизованно при завершении уровня или сцены.


Уничтожение контейнеров и вложенных объектов

Контейнеры (Container) могут содержать спрайты и другие контейнеры. Метод destroy у контейнера имеет опцию children:

container.destroy({ children: true, texture: true, baseTexture: true });
  • children: уничтожает все дочерние объекты.
  • texture: уничтожает текстуры спрайтов внутри контейнера.
  • baseTexture: освобождает GPU-память, связанную с базовыми текстурами.

Это позволяет безопасно удалить целые сцены или слои графики с минимальным риском утечек.


Принципы безопасного управления памятью

  1. Разделение спрайтов и текстур: спрайт можно уничтожать без удаления текстуры, если она будет использоваться повторно.
  2. Единая точка управления текстурами: хранение ссылок на BaseTexture и централизованное их уничтожение.
  3. Осторожное использование общих текстур: проверка, что текстура не используется в других спрайтах, перед уничтожением.
  4. Регулярный мониторинг GPU-памяти: особенно в играх с большим количеством графики, чтобы избежать падений FPS.

Оптимизация производительности

  • Использование Atlas и spritesheet снижает количество BaseTexture, что уменьшает накладные расходы на GPU.
  • Переработка сцен вместо постоянного создания новых текстур позволяет уменьшить нагрузку на сборщик мусора.
  • Для временных эффектов и анимаций можно использовать RenderTexture, которая создается в памяти и уничтожается после завершения эффекта:
const renderTexture = PIXI.RenderTexture.create({ width: 256, height: 256 });
// ... отрисовка в renderTexture
renderTexture.destroy(true);

Это особенно полезно для частой перерисовки сцен, частиц или динамических объектов.


Важные нюансы

  • destroy(true) нельзя применять к текстуре, которая все еще используется. Иначе возникает визуальный сбой на спрайтах.
  • Память в GPU не всегда освобождается моментально — это зависит от драйвера и браузера, но явное уничтожение BaseTexture гарантирует, что JS больше не держит ссылки.
  • RenderTexture требует отдельного управления, так как это отдельный ресурс в GPU и не связан напрямую с исходной текстурой.

Управление текстурами и памятью в PixiJS требует дисциплины и внимательности. Систематическое уничтожение спрайтов, текстур и базовых текстур позволяет поддерживать стабильную производительность даже в проектах с большим количеством графических ресурсов.