Three.js 内存释放问题
·
内存释放
1、常规方法:
beforeDestroy() {
try {
scene.clear();
renderer.dispose();
renderer.forceContextLoss();
renderer.content = null;
cancelAnimationFrame(animationID) // 去除animationFrame
let gl = renderer.domElement.getContext("webgl");
gl && gl.getExtension("WEBGL_lose_context").loseContext();
}catch (e) {
console.log(e)
}
}
常规方法不能彻底清除掉scene场景内的一些geometry、texture等,而且就算页面离开也不会自动释放内存。打开任务管理器,可以看到CPU一直被占用,切换页面时越来越高。
2、TrackResource 方法:
import * as THREE from 'three/build/three.module'
export default class ResourceTracker {
constructor() {
this.resources = new Set();
}
track(resource) {
if (!resource) {
return resource;
}
// handle children and when material is an array of materials or
// uniform is array of textures
if (Array.isArray(resource)) {
resource.forEach(resource => this.track(resource));
return resource;
}
if (resource.dispose || resource instanceof THREE.Object3D) {
this.resources.add(resource);
}
if (resource instanceof THREE.Object3D) {
this.track(resource.geometry);
this.track(resource.material);
this.track(resource.children);
} else if (resource instanceof THREE.Material) {
// We have to check if there are any textures on the material
for (const value of Object.values(resource)) {
if (value instanceof THREE.Texture) {
this.track(value);
}
}
// We also have to check if any uniforms reference textures or arrays of textures
if (resource.uniforms) {
for (const value of Object.values(resource.uniforms)) {
if (value) {
const uniformValue = value.value;
if (uniformValue instanceof THREE.Texture ||
Array.isArray(uniformValue)) {
this.track(uniformValue);
}
}
}
}
}
return resource;
}
untrack(resource) {
this.resources.delete(resource);
}
dispose() {
for (const resource of this.resources) {
if (resource instanceof THREE.Object3D) {
if (resource.parent) {
resource.parent.remove(resource);
}
}
if (resource.dispose) {
resource.dispose();
}
}
this.resources.clear();
}
}
这边封装了一个track方法,在页面直接调用即可。使用方法:
1、引入track,初始化
import ResourceTracker from "../../../common/3D/dispose";
// 在外层定义resMgr和track
let resMgr = new ResourceTracker();
const track = resMgr.track.bind(resMgr);
2、将所有的mesh、geometry、texture、object3D、外部加载的obj模型、gltf模型等等需要add to scene的物体,全部调用一下track方法
3、在vue的beforeDestroy内将这些track到的3D物体内存释放
beforeDestroy() {
try {
scene.clear();
resMgr && resMgr.dispose()
renderer.dispose();
renderer.forceContextLoss();
renderer.content = null;
cancelAnimationFrame(animationID)
let gl = renderer.domElement.getContext("webgl");
gl && gl.getExtension("WEBGL_lose_context").loseContext();
console.log(renderer.info) //查看memery字段即可
}catch (e) {
console.log(e)
}
}
在页面离开时查看console内的memory的字段可看到上一个页面scene是否全部释放干净。
全部都是0,说明内存释放完毕,此时再查看任务管理器,可以看到CPU使用率都是持平的。
参考文献:threejsfundamentals
更多推荐
已为社区贡献2条内容
所有评论(0)