内存释放

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
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐