Dispose: освобождение памяти GPU

В современных веб-приложениях, работающих с 3D-графикой, особенно критично контролировать использование ресурсов GPU. В библиотеке Three.js объекты, такие как геометрия, текстуры и материалы, после удаления из сцены не освобождают автоматически видеопамять. Для предотвращения утечек памяти используется метод dispose.


Dispose для геометрий

Каждая геометрия в Three.js (THREE.BufferGeometry) содержит буферы, хранящие данные вершин, нормалей, UV-координат и индексов. При удалении объекта из сцены эти буферы остаются в памяти GPU.

Пример освобождения геометрии:

const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });
const mesh = new THREE.Mesh(geometry, material);

scene.add(mesh);

// Удаление
scene.remove(mesh);
geometry.dispose(); // Освобождает буферы на GPU

Важно: вызывать dispose нужно после удаления объекта из сцены и если геометрия больше не используется нигде в коде.


Dispose для материалов

Материалы (THREE.Material) управляют шейдерами и текстурами. Помимо освобождения шейдеров, материалы могут содержать ссылки на текстуры.

Пример:

material.dispose();

Если материал использует текстуры, их необходимо освободить отдельно, так как dispose материала не освобождает связанные текстуры автоматически.


Dispose для текстур

Текстуры (THREE.Texture) могут занимать значительное количество видеопамяти, особенно при использовании карт высокого разрешения. Для их освобождения используется метод dispose:

texture.dispose();

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


Dispose для рендер-таргетов и буферов

Рендер-таргеты (THREE.WebGLRenderTarget) и буферы (THREE.DataTexture, THREE.DepthTexture) также занимают память GPU. Их очистка критична при динамическом создании текстур или использовании эффектов постобработки:

renderTarget.dispose();
dataTexture.dispose();

Практический подход: рекурсивный dispose

Для сложных сцен удобно создавать функцию, которая рекурсивно освобождает все ресурсы объекта и его потомков:

function disposeObject(obj) {
    if (obj.geometry) obj.geometry.dispose();
    if (obj.material) {
        if (Array.isArray(obj.material)) {
            obj.material.forEach(mat => mat.dispose());
        } else {
            obj.material.dispose();
        }
    }
    if (obj.texture) obj.texture.dispose();
    obj.children.forEach(child => disposeObject(child));
}

Использование такой функции гарантирует, что удаляемый объект не оставит «мусор» в GPU.


Контроль памяти

Three.js не предоставляет встроенного сборщика мусора для GPU. Для мониторинга состояния памяти можно использовать инструменты браузера:

  • Chrome DevTools → Performance/Memory
  • WebGL Inspector / Spector.js

Регулярное вызовы dispose после удаления объектов помогают избежать утечек и падения производительности при длительной работе приложения.


Рекомендации по использованию Dispose

  1. Всегда освобождать геометрии и материалы, когда объект больше не нужен.
  2. Текстуры удалять только после того, как они перестали использоваться во всех материалах.
  3. Рендер-таргеты и динамические буферы требуют явного dispose после завершения их использования.
  4. Использовать рекурсивные функции для сложных сцен с иерархией объектов.
  5. Проверять динамически создаваемые объекты на предмет повторного использования, чтобы не удалять ресурсы преждевременно.

Эффективное использование dispose позволяет значительно снизить нагрузку на GPU, предотвращает утечки памяти и обеспечивает стабильную работу приложений Three.js при динамическом создании и удалении объектов.