Чому Three.js витікає GPU-пам'ять
Збирач сміття JavaScript автоматично керує пам'яттю CPU. Але
об'єкти Three.js також утримують ресурси GPU —
буферні об'єкти, текстури, фреймбуфери — якими керують через API
WebGL. Збирач сміття не знає про них. Коли ви відкидаєте
Mesh, видаляючи посилання JavaScript, пам'ять GPU
залишається виділеною, доки ви явно не викличете
dispose().
У довготривалій симуляції, що регулярно створює й відкидає об'єкти, це накопичується в сотні мегабайтів витоку VRAM, зрештою спричиняючи збої або серйозне падіння продуктивності.
Перевірка симптомів: Відкрийте Chrome DevTools → Performance → Memory. Якщо пам'ять GPU постійно зростає під час роботи вашої симуляції (навіть коли візуально нічого не змінюється), у вас є витік.
Повний контрольний список
Геометрія
geometry.dispose(); // Звільняє буфери вершин та індексів
- Викликайте для кожного створеного
BufferGeometry - Геометрії InstancedMesh теж потребують звільнення
-
Об'єднані геометрії (з
mergeGeometries) — це нові об'єкти, звільняйте і їх
Матеріали
material.dispose(); // Звільняє скомпільовану шейдерну програму
- Викликайте для кожного підкласу
Material - Масиви матеріалів (меші з кількома матеріалами): пройдіться циклом і звільніть кожен елемент
- НЕ звільняє автоматично текстури — дивіться нижче
Текстури
// Ручне звільнення текстур
material.map?.dispose();
material.normalMap?.dispose();
material.roughnessMap?.dispose();
material.envMap?.dispose();
// ... усі властивості map
// Або за допомогою обходу
scene.traverse((obj) => {
if (obj.material) {
Object.values(obj.material).forEach(val => {
if (val?.isTexture) val.dispose();
});
}
});
Цілі рендерингу
renderTarget.dispose(); // Звільняє FBO + прикріплені текстури
Повний патерн демонтажу
function disposeMesh(mesh) {
mesh.geometry?.dispose();
if (Array.isArray(mesh.material)) {
mesh.material.forEach(disposeMaterial);
} else {
disposeMaterial(mesh.material);
}
}
function disposeMaterial(mat) {
if (!mat) return;
mat.dispose();
// Звільнення всіх текстур map
['map','normalMap','roughnessMap','metalnessMap',
'aoMap','emissiveMap','envMap','lightMap',
'bumpMap','displacementMap','alphaMap']
.forEach(key => mat[key]?.dispose());
}
// Демонтаж сцени
scene.traverse((obj) => {
if (obj.isMesh) disposeMesh(obj);
});
renderer.dispose();
renderer.forceContextLoss();
InstancedMesh
InstancedMesh — це просто Mesh —
звільняйте його геометрію та матеріал так само. Атрибути буферів
instanceMatrix та instanceColor
звільняються при звільненні геометрії.
Порада профі: Викликайте
renderer.info.reset() між сценами і виводьте в
консоль renderer.info.memory, щоб перевірити, що
лічильники геометрії та текстур обнуляються після вашого
демонтажу. Якщо ні — ви щось пропустили в dispose.