在vue开发SPA实际项目中,不止涉及到使用cesium可视化的大屏一个界面,在切换路由,页面或者关闭该功能、弹框后,cesium加载的模型,图层,实体等等信息会缓存到电脑的显存中,但是切回cesium界面的时候,又会重新进入页面的挂载周期,进行新的cesium实例的渲染,显存占用会越来越大,达到临界值后,页面会崩溃,显示out of memory或者是cesium页面红色弹框的shader错误
遇到问题要解决咯,首先肯定也是想到在页面destory()周期中进行卸载cesium的相关操作,但是也踩了很多坑,之前采用的方法就是直接给viewer清空并置空
viewer && viewer.destroy()
viewer = null
但是这样一直清除不干净,虽然比不清除之前好,显存还是会每次小幅度上升,因为viewer嵌套关系过多,这个可能只释放了viewer对象,但里面的很多图形信息,还是存在显存中的,今天找了套相对来说最干净的方法,直接上效果对比,注意看显卡的专用GPU内存占用情况,我的电脑显卡1660TI MAXQ,还没加载模型,重复来回点击十几次也会崩溃了
首先要注意一个老生常谈的问题,在vue框架中使用cesium,一定切记,不要把ceisum的相关对象放在响应式中! 这个嵌套的层级太深了,会严重影响性能,要不就用个let接收,要不就放在window中,如果其他页面也要使用和操作该cesium对象的话
修复之前
左侧第一个按钮为cesium的功能,第二个按钮是二维的leaflet功能,从第二个切到第一个按钮明显会看到显存曲线的上升趋势,但是从第一个切到第二个时,回落不明显,显存发生泄露,显存占用越来越大,风险很大
修复后效果
上升又回落
废话不多说,直接上干货,代码
注意下有个坑,那个primitives 不要removeAll,本来项目中也没有primitives,而且清除之后,在destory viewer会报错,所以就暂时先注释掉,后续有大神了解的话,可以解答下这个primitives为啥会出现这个问题
还有就是viewer.destory() 要放在前面哪些entities的removeAll后面,否则会报错导致不生效没清除干净,最后再都置为null
// 销毁cesium
destroyCesiumViewer() {
if (Cesium.defined(viewer)) {
viewer.entities.removeAll()
viewer.imageryLayers.removeAll()
viewer.dataSources.removeAll()
// viewer.scene.primitives.removeAll();
// 获取webgl上下文
let gl = viewer.scene.context._originalGLContext;
gl.canvas.width = 1;
gl.canvas.height = 1;
viewer.destroy(); // 销毁Viewer实例
gl.getExtension("WEBGL_lose_context").loseContext();
gl = null;
window.viewer = null;
var cesiumContainer = document.getElementById('cesiumContainer');
if (cesiumContainer) {
cesiumContainer.remove(); // 移除与地图相关的DOM元素
}
console.log('cesium销毁')
// 清理其他JavaScript对象和事件监听器
// ...
}