Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue 应用的内存泄露分析 #22

Open
ryancui92 opened this issue Apr 4, 2019 · 0 comments
Open

Vue 应用的内存泄露分析 #22

ryancui92 opened this issue Apr 4, 2019 · 0 comments

Comments

@ryancui92
Copy link
Owner

ryancui92 commented Apr 4, 2019

最近在做一个基于 Vue + ECharts 的大屏数据可视化应用时,发现在轮播时有大量的内存泄漏现象。单凭直觉与日常开发中看到的代码,考虑是以下几个原因:

  • ECharts 库 canvas 本身的内存泄漏
  • Vue 里各种监听器的没有及时销毁

因此在使用 devtool 的 Memory 定位问题时,亦沿着这个方向进行排查。

Chrome devtool Memory Tab 的用法大家自行 Google

对页面做一次 Memory Snapshot, 然后随意做一下轮播,再做一次 Snapshot 并切换到 Comparison 第一次快照。

image

按 Allocate Size 做个降序,可以看到 (array), (closure) 这些项排在了最前面。查看一下里面的内容。

没有及时销毁的监听器

image

点开其中一个 array, 发现里面有 V8EventListener/EventListener 的标记,而在代码里全局搜一下下面的事件名,便发现:

Vue.nextTick(() => {
  window.addEventListener('resize', this._resizeEventHandler, false);
  this._initOption();
})

在 Vue 实例中不停地添加监听器,但没有在销毁组件时及时销毁对应的监听器。

顺着这个思路可以把所有监听器导致的内存泄露都排查一遍。包括 window.addEventListener, Vue 的 bus.$on 之类的。

Vue 中过多的 Observer

在 Memory Tab 中还能看到一大堆这样的 get/set closure

image

这是 Vue 对对象属性做 Reactive getter 和 setter 的函数,打开里面一看,全是 echarts 的实例里的属性。此时我们发现,就是 Vue 把 echart instance 里的属性全部监听了:

new Vue({
  data: {
    instance: null // 这里
  }
})

但由于我们使用 echart 并不需要用到响应式的功能,因此我们把它从 data 中去掉,直接在 created 钩子中挂载 instance 变量就 ok 了。

created() {
  this.instance = null
}
@ryancui92 ryancui92 changed the title 记一次 Vue 应用的内存泄露分析 Vue 应用的内存泄露分析 Jul 31, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant