在咱们的项目中有一个可视化配置的模块,是经过go.js生成canvas来实现的。可是,咱们发现这个模块在浏览器中常常会引发该tab页崩溃。开启chrome的任务管理器一看,进入该页面内存和cpu就会暴涨,内存常常会飙到700多M。可是咱们的canvas实际的像素只有约500x500,根据一些粗略的计算,大概只占了1M的内存,这个计算过程可参考100*100的 canvas 占多少内存。那么咱们这700M内存是哪里来的呢?javascript
咱们可使用chrome开发者工具来分析咱们的调用栈。这边我是先经过Performance来帮助咱们定位问题,它会帮咱们生成一段过程当中一些数据的变化,包括js堆内存、dom节点数量、动画帧等数据,如图:vue
这是切换至一个canvas画布较大的一个模块的performance分析表现,能够看到占用了472M的内存。下面折线图蓝色部分是js堆内存的变化,而Main下面黄色与紫色的矩形框就是咱们的调用栈,上下两部分是按照时间一一对应的。能够看到,蓝色的折线呈高低起伏的态势,GC回收以后低点基本和高点持平,所以能够判定几乎不存在内存泄漏的问题。而后咱们能够放大去看一看,内存升高的时候,js作了些什么事情,找一找规律。java
咱们随机找一段内存增加的区域,能够看到在内存增加的过程当中,最为频繁调用的就是Observer相关的代码。可是就这么看,咱们不可以明白Observer是在干什么。此时咱们能够借用Memory选项中的Allocation Sampling按照javascript function来查看内存分配,咱们一样录制以上的一段操做。chrome
此时咱们可以清楚的看到,的确是这个Observer在做怪。同时,咱们能够看到这是vue的代码,点击右边的文件查看source code,就能够清楚的明白这就是vue在执行依赖收集的操做,此时会给属性添加watcher。那咱们这里为何会有如此多的属性被添加了watcher呢?看了一下代码,原来是我把go.js的一个实例挂到了vue的data选项中,放到data中的属性会被vue执行依赖收集的相关操做,而这个实例拥有很是多的嵌套属性,所有都会被添加watcher。其实,咱们只是想单纯的存储一下这个实例,供咱们后续调用其相关的方法,添加watcher对咱们来讲彻底没有意义,那咱们如何避免这样的问题呢?canvas
上网搜索了相关的解决方案,大概有以下几种:浏览器
javascript data() { return { $goDiagram: null } }
可是这样声明,在template中引用时会报找不到$goDiagram属性的错误,具体的缘由我还没深究,有空能够研究一下。export default { goDiagram: null, mounted() { this.$options.goDiagram = xxx } }
这应该是比较好的一个方法,vue官方中也说明了$options用来包含自定义属性,例如咱们平时引入的常量或是枚举类型,咱们也不但愿它们被添加无心义的watcher,所以能够经过这种方式来定义,在template中引用时只须要{{$options.xxx}}便可。这种方式惟一的缺点就是不能像data那样一眼望去就能清楚地知道你定义了什么属性。
项目中我采用了第一种方式,通过修改后内存占用量减小到原来的1/5到1/6,能够说效果很是好,不再会出现浏览器崩溃的状况了。dom
经过这样的一个问题,咱们主要可以学习到两点:工具