当前位置: 首页 > Web前端 > HTML

Vue单页应用中内存泄漏的定位与修复(一)

时间:2023-04-02 16:42:03 HTML

在前端项目(PC端)中,定位内存泄漏往往比修复更难。尽管谷歌浏览器提供了Memory工具,但面对成千上万的元素和错综复杂的引用关系,开发仍然很难快速定位到有问题的代码块。1.什么是内存泄漏?系统进程不再使用的内存没有及时释放,称为内存泄漏。当内存占用越来越高时,轻则影响系统性能,重则导致进程崩溃。Chrome限制了浏览器可以使用的内存上限(64位是1.4GB,32位是1.0GB),这意味着浏览器将无法直接操作一些大内存对象。V8引擎在进行垃圾回收时,会阻塞JavaScript应用逻辑,重新执行JavaScript应用逻辑,直到垃圾回收结束。这种行为称为“停止世界”。如果V8的堆内存是1.5GB,V8做一次小垃圾回收需要50ms以上,造成假死。2.JS内存管理和垃圾回收机制GC高级语言基本上都有垃圾回收机制(garbagecollection)来自动管理内存,减轻程序员的负担,达到解决内存泄漏的目的,但是不允许手动触发和内存管理任何干预措施。旧版浏览器采用引用计数方式(ReferenceCounting)来管理内存,即每次引用加一,释放时减一。当这个值的引用计数变为0时,它的内存空间就可以被回收了。缺点是循环引用时不能回收。现代浏览器基本都是采用mark-and-sweep的方式来管理内存,即浏览器周期性地从某个根元素(比如window对象)开始寻找引用变量以及这些变量所引用的变量,从而使其始终发现下降。能找到的变量就是可用变量,找不到的变量会被内存回收。缺点是内存在清空后会产生很多细粒度的block,所以派生出mark-organization的方法,不再赘述。3、VUE中容易出现内存泄漏的几种情况。内存泄漏是一个累积的过程。只有当页面的生命周期稍长时,问题才会暴露出来。频繁的互动可以加快积累的过程。问题暴露了(所谓刷新可以满血复活)。所以很多时候,我们都是被动的等待问题暴露出来,然后再进行排查。主动分析通常比较困难。Vue页面大多是单页应用,交互性强,停留时间长。如果处理不当,很容易发生内存泄漏。本文主要针对自由dom对象的考察,普通JS变量的考察有时间会补充。1.全局变量引起的内存泄漏这个页面的dom对象在全局window对象中被引用name:'home',node:document.getElementById('home')}}}按Heapsnapshots键,搜索Detached,发现有没有dom脱离文档树元素,属于正常现象,换个路由跳转到其他页面,按Heapsnapshots键,搜索Detached,发现当前页面有两个dom元素浮在外面,它很明显,window对象引用了主页中的div,即使这个时候主页已经被销毁,home中的dom元素仍然驻留在内存中,无法释放。解决方法是在页面卸载的时候顺便处理掉引用。2.除了直接引用,window的native方法也会起到引用dom元素的作用,使其无法释放。解决方法一样,在销毁页面的时候,顺便解引用并释放内存mounted(){window.addEventListener('resize',this.func)},beforeDestroy(){window.removeEventListener('resize',this.func)}3.一些使用不当全局方法也会导致内存释放失败,也可以考虑在页面卸载时解引用mounted(){this.$EventBus.$on('homeTask',res=>this.func(res))},destroyed(){this.$EventBus.$off()}自由dom节点的原因很多,不止这三个,总结一下:1.window对象,事件总线,全局vuex都绑定到被销毁页面的节点上。届时,节点不会随页面一起销毁。2.使用第三方库创建实例。第三方库一般会提供销毁函数,页面跳转销毁函数时调用不正确3、有的同学会说在页面中使用闭包也会造成内存泄漏。Vue框架中有内存管理机制。只要写对了,理论上是不会造成内存泄漏的。