vue项目中整合Cesium在某些页面老是崩溃和卡顿,一般Vue项目内存泄露常发生在某些地方我们引用的第三方库自己创建和维护了DOM,所以Vue在页面卸载时虽然这些对象的引用都释放了,但是因为这些对象自身关联了DOM所以内存无法释放,但是我们项目中已经在destroyed 阶段做了内存释放。

这是项目结构的伪码:

export default {
  $_viewer: null,
  data () {
    return {
      gridDataSource: null
    }
  },
  methods: {
    generateBuilding () {
      let _this = this
      getAllGridByBuildingId(_this.modelData.buildingId).then(resp => {
        _this.gridDataSource = new GridsBuildingDataSource()
        gridDataSource.load(resp.data)
        _this.$_viewer.dataSources.add(_this.gridDataSource)
      })
    }
  },
  destroyed () {
    if (this.$_viewer) {
	  // whether to destroy the data sources in addition to removing them.
      this.$_viewer.dataSources.removeAll(true)
      this.$_viewer.destroy()
    }
    this.$_viewer = null
  }
}
  • 第一步:解决进入页面容易导致页面崩溃的问题

通过内存分析工具,发现在正常页面绘制网格数量级达到万级才900MB左右,但是该页面2000左右就达到了900MB,所以应该是某些地方对某些变量进行的复制或者添加了多余监听之类的,首先是找到这个点,万幸的是我们通过Chrome内存分析工具分析了几个相似页面,只在某些页面出现了这个问题,通过比对代码差异,发现出现内存泄露的页面都在data中对自定义的DataSource进行了引用,我们知道Vue对data中的数据都会进行代理,难道是代理过程中复制了值或者添加了大量监听引起的内存翻倍?

我们试着改造了下代码,我们知道Vue私有变量或者方法采用$或者_开头是不会生成代理的,改造代码如下:

data () {
    return {
      $gridDataSource: null
    }
},

果然如我们所料,内存翻倍的问题解决。

  • 第二步:解决内存泄露问题

在代码运行一段时间后我们发现还是会出现内存增长的问题,继续分析,当我们从上述页面出来后,我们使用Chrome工具Heap snapshot截取内存后发现,在离开这些页面后DataSource并没有释放。

继续对比正常页面代码,唯一不同还是在DataSource的引用上,继续使用Chrome内存分析,发现依然被Vue引用:

修改destroyed里方法:

  destroyed () {
    if (this.$_viewer) {
      this.$gridDataSource = null
	  // whether to destroy the data sources in addition to removing them.
      this.$_viewer.dataSources.removeAll(true)
      this.$_viewer.destroy()
    }
    this.$_viewer = null
  }

结果依然还是没有释放,考虑是不是Vue还是对定义在其内部的属性做了某些操作导致释放不彻底?我们决定把DataSource提出Vue对象作用域:

let gridDataSource = null
export default {
  destroyed () {
    if (this.$_viewer) {
      gridDataSource = null
	  // whether to destroy the data sources in addition to removing them.
      this.$_viewer.dataSources.removeAll(true)
      this.$_viewer.destroy()
    }
    this.$_viewer = null
  }
}

问题解决!!