vue单页应用的内存泄露定位和修复问题小结


Posted in Javascript onAugust 02, 2019

在前端项目(PC端)中,内存泄露的定位往往比修复更加困难,即使google浏览器有提供Memory工具,但是面对成千上万的元素和错综复杂的引用关系,开发则依然很难快速定位到问题代码块。

一、什么是内存泄漏?

系统进程不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。当内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。Chrome限制了浏览器所能使用的内存极限(64位为1.4GB,32位为1.0GB),这也就意味着浏览器将无法直接操作一些大内存对象。

V8引擎在执行垃圾回收时会阻塞 JavaScript应用逻辑,直到垃圾回收结束再重新执行JavaScript应用逻辑,这种行为被称为“全停顿”(stop-the-world)。 若V8的堆内存为1.5GB,V8做一次小的垃圾回收需要50ms以上,造成假死现象。

二、JS内存管理和垃圾回收机制GC

高级语言基本都有垃圾回收机制(garbage collection)自动管理内存,降低程序员的负担,以达到解决内存泄漏的目的,但是不允许人为手动触发,无法对内存管理进行任何干预。

老版本的浏览器使用引用计数法(Reference Counting)来管理内存,即每次引用加一,被释放时减一,当这个值的引用次数变成 0 时,就可以将其内存空间回收,缺点是循环引用时无法回收。

现代浏览器基本采用标记清除法(Mark-and-Sweep)来管理内存,即浏览器周期性地从某个根元素(譬如 window 对象)开始找引用变量,及这些变量引用的变量,这样一直找下去。能找到的变量为可获得变量,不能找到的将被内存回收。

vue单页应用的内存泄露定位和修复问题小结

缺点是清除后内存会产生很多细化的分块,所以又衍生了标记-整理法,不细讲。

vue单页应用的内存泄露定位和修复问题小结

三、VUE中容易出现内存泄露的几种情况

内存泄露是一个累积的过程,只有页面生命周期略长的时候才暴露出问题,频繁交互能够加快累积的过程,偏展示的页面很难把这样的问题暴露出来(所谓刷新一下又能满血复活)。所以很多时候我们都是被动式的等待问题暴露然后进行排查的,主动式的分析通常比较难。vue页面大多是单页应用,高交互且停留时间久,处理不好很容易出现内存泄漏。本文章 主要针对游离的dom对象进行排查 ,普通的JS变量排查有时间再补充。

1.全局变量造成的内存泄露

<template>
 <div id="home">
  这里是首页
 </div>
</template>

<script>
export default {
 mounted () {
  window.test = { // 此处在全局window对象中引用了本页面的dom对象
   name: 'home',
   node: document.getElementById('home')
  }
 }
}
</script>

按下Heap snapshots键,搜索Detached,发现没有脱离文档树的dom元素,属于正常现象

vue单页应用的内存泄露定位和修复问题小结

改变路由跳转到other页面,按下Heap snapshots键,搜索Detached,发现有两处dom元素游离于当前页面之外,很明显是window对象引用了home页面中的div,即使此时home页面已经销毁,home中的dom元素却还驻留在内存中无法释放。

vue单页应用的内存泄露定位和修复问题小结

解决方案就是在页面卸载的时候顺便处理掉该引用。

<template>
 <div id="home">
  这里是首页
 </div>
</template>

<script>
export default {
 mounted () {
  window.test = { // 此处在全局window对象中引用了本页面的dom对象
   name: 'home',
   node: document.getElementById('home')
  }
 },
 destroyed () {
  window.test = null // 页面卸载的时候解除引用
 }
}
</script>

2.除了直接引用,window的原生方法也会起到引用dom元素使其无法释放的效果。

<template>
 <div id="home">这里是首页</div>
</template>

<script>
export default {
 mounted () {
  window.addEventListener('resize', this.func) // window对象引用了home页面的方法
 },
 methods: {
  func () {
   console.log('这是home页面的函数')
  }
 }
}
</script>

vue单页应用的内存泄露定位和修复问题小结

 解决方法一样,也是在页面销毁的时候,顺便解除引用,释放内存

mounted () {
  window.addEventListener('resize', this.func)
},
beforeDestroy () {
  window.removeEventListener('resize', this.func)
}

3.一些全局的方法使用不当也会造成内存无法释放,在页面卸载的时候也可以考虑解除引用

<template>
 <div id="home">这里是首页</div>
</template>

<script>
export default {
 mounted () {
  this.$EventBus.$on('homeTask', res => this.func(res))
 },
 methods: {
  func (res) {
   console.log(res)
  }
 }
}
</script>

vue单页应用的内存泄露定位和修复问题小结

mounted () {
 this.$EventBus.$on('homeTask', res => this.func(res))
},
destroyed () {
 this.$EventBus.$off()
}

造成游离dom节点的原因还有很多,不止这三种,总结起来:

1.window对象、事件总线、全局vuex上绑定了已销毁页面上的节点,到时节点不随页面一起销毁

2.使用第三方库创建实例,第三方库一般会提供销毁函数,页面跳转时没有调用正确的销毁函数

3.有同学会说在页面中使用闭包也会造成内存泄露,在vue框架里有管理内存的机制,只要按照它的正确编写方法,理论上是不会造成内存泄露的

总结

以上所述是小编给大家介绍的vue单页应用的内存泄露定位和修复问题小结,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
子窗体与父窗体传值示例js代码
Aug 01 Javascript
js showModalDialog参数的使用详解
Jan 07 Javascript
js实现仿网易点击弹出提示同时背景变暗效果
Aug 13 Javascript
js流动式效果显示当前系统时间
May 16 Javascript
JS匹配日期和时间的正则表达式示例
May 12 Javascript
详解ajax的data参数错误导致页面崩溃
Apr 30 Javascript
通过webpack引入第三方库的方法
Jul 20 Javascript
vue3.0 CLI - 2.2 - 组件 home.vue 的初步改造
Sep 14 Javascript
vue-cli2.0转3.0之项目搭建的详细步骤
Dec 11 Javascript
微信小程序之onLaunch与onload异步问题详解
Mar 28 Javascript
Vue中对iframe实现keep alive无刷新的方法
Jul 23 Javascript
详解在IDEA中将Echarts引入web两种方式(使用js文件和maven的依赖导入)
Jul 11 Javascript
vue回到顶部监听滚动事件详解
Aug 02 #Javascript
微信小程序npm引入vant-weapp的踩坑记录
Aug 01 #Javascript
vue3.0中的双向数据绑定方法及优缺点
Aug 01 #Javascript
微信小程序导入Vant报错VM292:1 thirdScriptError的解决方法
Aug 01 #Javascript
微信小程序使用Vant Weapp组件库的方法步骤
Aug 01 #Javascript
微信小程序中button去除默认的边框实例代码
Aug 01 #Javascript
vue-router两种模式区别及使用注意事项详解
Aug 01 #Javascript
You might like
一个基于PDO的数据库操作类(新) 一个PDO事务实例
2011/07/03 PHP
利用PHP扩展vld查看PHP opcode操作步骤
2013/03/04 PHP
基于php-fpm的配置详解
2013/06/03 PHP
CodeIgniter错误mysql_connect(): No such file or directory解决方法
2014/09/06 PHP
PHP通过bypass disable functions执行系统命令的方法汇总
2018/05/02 PHP
Javascript中设置默认参数值示例
2014/09/11 Javascript
javascript运算符——逻辑运算符全面解析
2016/06/27 Javascript
jquery 多个radio的click事件实例
2016/12/03 Javascript
touch.js 拖动、缩放、旋转 (鼠标手势)功能代码
2017/02/04 Javascript
基于jQuery实现咖啡订单管理简单应用
2017/02/10 Javascript
Vue.js如何优雅的进行form validation
2017/04/07 Javascript
vue2.0 与 bootstrap datetimepicker的结合使用实例
2017/05/22 Javascript
浅谈Vue 初始化性能优化
2017/08/31 Javascript
bootstrap+jquery项目引入文件报错的解决方法
2018/01/22 jQuery
vue-router相关基础知识及工作原理
2018/03/16 Javascript
微信小程序滑动选择器的实现代码
2018/08/10 Javascript
jQuery内容过滤选择器与子元素过滤选择器用法实例分析
2019/02/20 jQuery
vue双向绑定及观察者模式详解
2019/03/19 Javascript
微信小程序用户授权、位置授权及获取微信绑定手机号
2019/07/18 Javascript
[04:27]2014DOTA2国际邀请赛 NAVI战队官方纪录片
2014/07/21 DOTA
[03:04]2018年国际邀请赛典藏宝瓶&莱恩声望物品展示 片尾有彩蛋
2018/06/04 DOTA
利用Python批量提取Win10锁屏壁纸实战教程
2018/03/27 Python
Windows系统下PhantomJS的安装和基本用法
2018/10/21 Python
Pytorch对Himmelblau函数的优化详解
2020/02/29 Python
python实现对变位词的判断方法
2020/04/05 Python
Opencv图像处理:如何判断图片里某个颜色值占的比例
2020/06/03 Python
python利用蒙版抠图(使用PIL.Image和cv2)输出透明背景图
2020/08/04 Python
Vector, ArrayList, HashTable, HashMap哪些是线程安全的,哪些不是
2015/10/12 面试题
机电专业毕业生求职信
2013/10/27 职场文书
质检员的岗位职责
2013/11/15 职场文书
测试工程师岗位职责
2013/11/28 职场文书
公务员综合考察材料
2014/02/01 职场文书
迟到检讨书2000字(精选篇)
2014/10/07 职场文书
公司联欢会主持词
2015/07/04 职场文书
运动会宣传语
2015/07/13 职场文书
python使用shell脚本创建kafka连接器
2022/04/29 Python