问题背景
最近一年多在做的项目是一个大数据的产品平台, 做一些数据类的产品, 主要是做一些客户的分群筛选, 客户画像, 策略配置之类的功能, 项目使用的技术栈是vue, 项目的一些产品页会被公司的几个其他的平台调用. 出现问题的这个页面是一个用户的画像页, 调用方是业务方坐席的使用平台, 一个运行在IE上的项目, 调用的方式是使用iframe将页面嵌入.
问题的产生
周一我们收到邮件, 说我们的画像页面在生产上被调用之后,IE的内存会持续升高,每查看一个新客户的信息 内存的增长量在28M左右, 这个问题导致差不多每隔1-2小时, 坐席的IE浏览器就会卡死, 必须重启.
问题的分析
看到问题之后, 我们想到的问题产生原因可能是由于:
一、前端页面存在内存泄漏,项目组后端不熟悉vue的同事会想到是不是vue不兼容ie, 然后还存在内存泄漏的问题。
二、后端排查接口调用内存泄漏的问题.
三、调用iframe 之后, 内存没用释放, 然后坐席由于要查看客户信息, 又会不断调用,所以内存的占用会持续不断地增加.
问题的解决
我们从上面想到的三个方面入手, 对问题产生的原因进行了排查.
首先排除vue项目不兼容+前端内存泄漏
对方项目使用的ie版本是ie的edge版本, 而vue是兼容ie9及以上版本的, 之所以不兼容ie8 及以下版本是因为, ie8 不支持ES5的Object.defineProperty()属性, 所以首先就排除了兼容性的问题, 至于内存泄漏的问题, 一般前端的内存泄漏问题大体出现在事件注册上或者一些使用过但未释放的 dom 节点, 我们这个页面就是一个很简单的纯展示性的页面, 除了筛选客户, 然后就没有其他交互功能, 用Profiles面板查看页面的内存之后,发现每次页面打开操作之后的内存占用量最多也就17M, 而且也没有怎么发现内存持续升高的问题.
然后,后端查看了页面的接口调用返回情况
我们发现在接口调用在返回数据之前, ie的内存确实会短暂增高, 后端的代码存在一定的内存泄漏问题, 但是后面后端代码优化之后, 接口查询时间慢则0.19s, 快的话只要0.05s, 并且后端接口调用返回之后, 内存又会降下来, 所以,ie内存持续增高的根本原因也不是因为接口返回.
最后我们经过测试发现, 问题的根本原因确实是ie调用iframe 之后, 内存没有释放导致的.
网上重点查看了一些ie内存泄漏的问题, 发现ie在iframe元素的回收方面确实存在着bug. 然后这个问题的产生的内存增长基本的解决办法网上的资料基本上全都是
将iframe元素的src属性值修改为”abort:blank”,然后把脚本中引用它的变量置空并调用CollectGarbage(), 相关的代码如下:
var frame = document.getElementById('iframe');//获取到iframe对象
frame.src = 'about:blank'; //src地址置空
frame.contentWindow.document.write('');//清空iframe的内容
frame.contentWindow.close();//避免iframe内存泄漏
CollectGarbage();//这个方法为IE下独有,做内存释放之用,这里加上可以保险一点
但是亲测, 如下的办法根本不能解决我们项目中ie内存持续增高的问题, 我们查看调用方的代码发现, 对方每次更新客户信息的方式是重置页面的src地址, 我们即使在重置src地址之前调用上面的方法,内存增量也只是稍微有所减缓, ie上测试结果还是每次打开一个新客户的页面, 内存依旧增长20M左右.
后面我们想到在内存依旧增长的原因是由于重置之前iframe标签的src之前, 将src置空, 然后调用CollectGarbage()进行垃圾回收的时间不够, 所以想到将src延迟50-100ms再重置, 后面发现这个办法果然有一定效果, 采用这样的办法之后发现, 页面的内存增长到300M之后,再往上增长的速度基本上就降下来了, 但是如果我们写代码一秒刷新一次页面的话, 十几分钟下来, 页面的内存还是会有缓慢增长, 但还是能控制在300M左右. 至此, 我们觉得这个问题有了一个短暂的临时解决方案.
临时方案不能长久, 后面我们讨论之后想到,既然是重置src引发的问题, 那么能不能不重置iframe的src, 而是通过postMessage 传参给我们被调用方, 我们拿到消息再通知后端更新页面信息, 这样不就将问题解决了么, 后面我们一测试, 发现改成这样之后, 内存增长的问题果然被解决了, 父页面向子页面传参的代码如下:
var frame = document.getElementById('iframe');//获取到iframe对象
frame.contentWindow.postMessage(data, *);//清空iframe的内容
子页面接收传参后处理数据的代码如下
window.addEventListener('message', callBackFn, false);
子页面接收到消息之后重新调接口更新页面内容的代码写在callBackFn方法里面就行了,至此, 这个问题就彻底得到解决了. 记录一下,供有需要的同学参考.✿✿ヽ(°▽°)ノ✿

在IE项目中,使用iframe嵌入页面后出现内存持续升高的问题,每查看一个新客户信息,内存增长约28M,导致浏览器卡死。分析原因包括前端内存泄漏、后端接口内存泄漏和iframe内存未释放。通过排查,发现根源是ie对iframe元素的回收存在bug。尝试将iframe src设为"about:blank"并调用CollectGarbage()效果有限。最终,通过延迟重置src并使用postMessage传递参数,成功解决内存增长问题,实现页面内存稳定。

584

被折叠的 条评论
为什么被折叠?



