温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

JS如何解决内存泄漏页面崩溃问题

发布时间:2022-08-17 09:44:19 来源:亿速云 阅读:429 作者:iii 栏目:开发技术

这篇“JS如何解决内存泄漏页面崩溃问题”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“JS如何解决内存泄漏页面崩溃问题”文章吧。

死去的页面突然攻击我?

因为项目本身过于庞大,且用户反馈不特定页面崩溃,这使得问题定位难度较大。

经过团队的讨论认为可能是该用户的组织架构接口数据量过大,当数据到达页面后需要经过递归处理,导致内存不足,且通过调试发现并非初次调用该接口就会导致崩溃,而是需要多次调用才会出现该问题。

而且在调试的过程中还发现因数据量过大,该接口需要长达 30s 的时间才能返回。而这么长的时间用户可能已经离开这个页面了。我们尝试以这个场景进行操作发现,用户离开页面并没有取消已经发出的请求,当该请求响应后会导致内存占用飙升。

因该接口为项目全局接口,经过讨论我们决定先修复这个离开页面不取消请求的问题,测试能否解决崩溃问题。

JS如何解决内存泄漏页面崩溃问题

陷入僵局

当我们在离开页面时取消未完成的请求后,测试反馈仍然会不定时崩溃,此时的我们有点无从下手了。因为我们发现问题貌似有点大了。

此时我们已经开始怀疑出现了内存泄漏,于是我们祭出了 chrome-devtool 使用 Memory 来进行内存占用分析。

JS如何解决内存泄漏页面崩溃问题

经过内存分析发现,内存中存在大量的分离元素未能及时回收。我按照内存快照的指引开始了漫长的修改。两天的修改后发现,虽然修复了不少的问题,但是仍然不能有效的降低页面的内存占用,每当我们跳转新的页面时某些页面仍然不能正常释放。此时我为了高效定位问题,开始使用绝招——删代码。

  • 将页面中的组织架构树删除——内存占用没降下来...

  • 将页面的列表删除——很棒空页面果真降下来了

  • 将组织架构树加上,列表删除——内存又起来了...

此时的我认为组织架构树的写法有问题,所以花了两天的时间过了一遍组织架构树的代码,未发现有什么异常的地方。

为了确认是组织架构树的问题还是页面列表的问题,我在项目中新建了两个空白的路由页面。在这个页面中单独使用这两个组件,都没有问题。

问题陷入了僵局...

垂死病中惊坐起

在我们修复这个问题的期间,另一个用户也反馈了相同的问题过来,不过用户说他用的是edge浏览器。此时同事说edge好像可以撑的更久一点。????哇,真的吗?难道和浏览器有关系?

于是我又打开了edge浏览器,点开了devtool点开了Memory...哎?这是什么

JS如何解决内存泄漏页面崩溃问题

edge的devtool这么好吗,专门有独立的标签用来查找分离的元素啊,蛮人性化的嘛。可是这和chrome不一样呀,咋用呢?(戳这里)

JS如何解决内存泄漏页面崩溃问题

它真的好智能,竟然已经把所有泄漏的dom按照结构组织好了,这样就不用我再从一堆内存信息中一个个找它们的关联关系了。

从上图我发现原来是有一个全局的tip()方法导致了整个页面没能正常回收,用户每进一次这个页面就会在内存里多一份这个页面的dom节点。而这个页面又有完整的组织架构树,组织架构树又很大...

查看了tip()方法的源码发现,这是一个全局的指令,这个指令每次都会创建一个新的tip对象,而这个tip对象与页面上的dom节点关联,且永远不会被销毁。

类似的问题在列表中有个对表格行拖拽排序的功能,使用了第三方包sortablejs而未调用destory()方法销毁sortable 实例,进而导致表格与页面也未能正确释放。

勿以善小而不为

到此,大概的原因已经明确了。未及时销毁的无用对象导致了大面积的内存泄漏,叠加用户的配置较低(8G内存,且开启了很多页面),导致了页面的崩溃。

类似以上的问题在本次修复中还发现不少,如:

  • 公共弹窗组件将传入的子组件持有,在关闭弹窗后未能销毁子组件。

  • 全局的EventBus实例未及时调用$off方法销毁事件,而事件回调与页面又产生关联(如:$refs、$parents)

  • 组件接受来自页面的方法,而该组件未能在页面离开时销毁(如在组件内将组件的this绑定在window上),导致整个页面不能释放

  • 为了在页面resize时能够调节echarts大小,在window上绑定了resize回调,离开页面时为清除resize事件

  • 组件实例化时在document上绑定click事件后,销毁组件时为清除click事件

以上的每一个问题都是小问题,仅仅是因为没用在beforeDestroy中调用Element.removeEventListener()或者未调用destroy()方法。但是会导致很大的后患。

修复后的页面已经能够达到较为正常的内存占用了,在此给大家放一张测试同学提供的修复前后的内存占用对比图,相较于修复前的内存占用只增不减(峰值4G,然后崩溃)到现在的能及时回收(最复杂的页面峰值500M,普通页面100M以内),已经有了极大的提升。

JS如何解决内存泄漏页面崩溃问题

JS如何解决内存泄漏页面崩溃问题

修改参考

const handleResizeWindow = () => {
    myChart.resize();
}
window.addEventListener("resize", handleResizeWindow);
this.$once('hook:beforeDestroy', () => {
    myChart.dispose() // 销毁echart实例
    window.removeEventListener('resize', handleResizeWindow)
})
created () {
    window.removeEventListener('beforeunload', this.closePage)
},
...
beforeDestroy () {
    window.removeEventListener('beforeunload', this.closePage)
}
 mounted() {
     this.$eventBus.$on("eventName", this.handleEvent);
     this.$once('hook:beforeDestroy', () => {
         this.$eventBus.$off('eventName', this.handleEvent)
     })
 }

以上就是关于“JS如何解决内存泄漏页面崩溃问题”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

js
AI