全动态前端页面架构(full ajax)中是如何处理Javascript内存泄露问题的? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
breeswish
V2EX    Javascript

全动态前端页面架构(full ajax)中是如何处理Javascript内存泄露问题的?

  •  
  •   breeswish 2013-03-31 13:55:29 +08:00 via Android 7333 次点击
    这是一个创建于 4581 天前的主题,其中的信息可能已经有所发展或是发生改变。
    关于“全动态前端页面架构”可能不是很专业,总之我不知道最专业名词是什么= =

    这个名词描述的是这样一种网站: 它的所有页面都是使用ajax加载并进行呈现的 局部刷新应用到了所有页面上

    举例: google plus / jsgen

    我打算在一个需求多样化并且前端功能比较rich的网站中使用这个技术(比如类似于google+)。


    于是在全动态页面架构中 我主要想到了3方面的问题: 加载,内存,资源。以下是详细问题,不知大家有没有什么成熟的方案?

    1.
    加载上,应当一次性加载所有js呢还是按需加载?如果按需加载的话如何确保不会多次加载(conflict)?

    另外加载某个页面时候如何知道它需要哪些js?

    2.
    内存上,如果是按需加载的话 并且假设js不会重复加载,那么势必随着用户点击页面越来越多,加载并贮存在浏览器中的js也会越来越多(最后内存的占用接近于甚至超过一次性加载解析所有js?) 有没有什么办法可以使得加载新页面时候有效释放上一个页面的js内存占用?

    3.
    资源泄露。

    加载新页面时候不能释放上一个页面引入的js对象是一种内存泄露,然而还有更多可以泄露的,比如setInterval()创建的计时器。

    假设页面A创建了一个计时器,然后切换到了页面B,那么这个计时器显然还在工作。如何有效地对这些资源进行综合性托管?(我希望有一种先期预防的模型,类似于一种context sandbox,而不是等到发现有泄露了再修复BUG)

    另外还有DOM。假设页面A使用了TinyMCE,用户使用TinyMCE弹了个浮动窗(append in body),然后直接进入了页面B,那么这个Tinymce的浮动窗是不归自己控制的,根本抓不到除非重写。这种由于第三方内容引入的资源不可控怎么办?

    最后还有Javascript对象的泄露问题,这种内存泄露好像根本无法进行预防?

    ==========

    说一下我自己曾经做的一个架构:

    1. 按需加载
    加载页面时候先获取要加载哪些js 然后加载之(如果已加载则忽略) 最后加载相关页面。

    2. 资源上下文
    随着每个页面分配一个资源上下文的对象,存储timer/intervalTimer/野生DOM,在切换页面时候进行资源释放。但是!它提供了托管的接口,却无法直接让所有东西都托管下来: 必须得开发者自己遵循规则使用其接口才行,于是最大的问题就是第三方库这种不遵循规则的怎么办?

    可以看到这样一个架构实际上仍然不能从根本上解决资源泄露问题,严重对第三方库的资源泄露敏感。
    另外,它也不能释放JS本身占用的内存(只能释放DOM/Timer)。

    因此来请教大家,有没有什么好的想法?

    (注意 一切问题都是由rich client和动态页面加载产生的)
    18 条回复    1970-01-01 08:00:00 +08:00
    cj1324
        1
    cj1324  
       2013-03-31 20:10:38 +08:00
    关注~ 这个环境下第三方库的选择应该谨慎
    iinterest
        2
    iinterest  
       2013-03-31 22:55:40 +08:00
    OPOAOne Page,One Application
    下面的问题好多,好复杂啊,先去洗澡了。。。
    breeswish
        3
    breeswish  
    OP
       2013-03-31 23:11:54 +08:00 via Android
    @cj1324 是的!后来tinymce我干脆丢进一个iframe…
    andy12530
        4
    andy12530  
       2013-04-01 01:07:36 +08:00 via iPhone   1
    我来歪个楼。
    这种应该叫 富web应用

    加载的话require js seajs之类有加载器,构建无刷新富应用采用backbone 轻量级框架。

    每个页面要加载什么 需要开发者定义 也就是依赖。
    0x0001
        5
    0x0001  
       2013-04-01 07:49:10 +08:00   1
    这叫Ria应用
    其实真的必须都在一个页面么?不要为了炫技而开发…
    用户体验才是重点,必要的跳转没发现什么不妥。

    我更担心的日你代码的可读性和维护性
    cmonday
        6
    cmonday  
       2013-04-01 08:04:52 +08:00 via Android   1
    都复杂到这个程度了竟然没有引入 requirejs ozjs 或者 seajs 这种依赖管理库么?你的这些问题前人早就遇到过而且解决过了
    不可控的第三方库丢进 iframe 是对的,不过你仔细研究一下它的接口的话,我相信大多数时候都是可控的
    est
        7
    est  
       2013-04-01 08:35:49 +08:00
    有些内存泄露是浏览器js引擎的bug。你没法解决的。Google的GWT团队跟IE团队多次搞基成功修复了各种诡异bug。
    anhulife
        8
    anhulife  
       2013-04-01 10:00:00 +08:00   1
    我们公司最近在做类似的应用
    我们的解决方案是
    每个页面、组件都是一个模块,模块之间有依赖关系

    1 JS加载 RequireJS 负责加载JS和处理依赖,首先加载的是libs.js和app.all.js,都是些共用的JS,然后把分业务打包JS,按需加载

    2 由于使用了RequireJS加载JS,所以不会出现重复加载的场景

    3 每个模块都负责管理资源,比如模块里面有setInterval,那在模块销毁的时候,需要销毁setInterval,事件绑定也是这样的,这样能够有效地释放资源

    我们使用的库有:
    RequireJS jQuery Backbone.js Underscore.js mustache.js Grunt
    Frannk
        9
    Frannk  
       2013-04-01 10:07:23 +08:00
    用Backbone常见的内存泄露是视图替换的时候没有删除view(相应的事件绑定),而只是删除了dom
    把这个问题克服就够了
    NemoAlex
        10
    NemoAlex  
       2013-04-01 10:15:50 +08:00
    我想,楼主说的是模块化管理代码和变量的问题吧?不是内存泄漏。
    看标题我还以为现在写前端的人都要想着检查内存泄漏了...
    heroicYang
        11
    heroicYang  
       2013-04-01 10:28:56 +08:00
    @Frannk 现在直接使用remove不仅会删除dom也会移除事件绑定
    heroicYang
        12
    heroicYang  
       2013-04-01 10:29:57 +08:00
    @NemoAlex 呃...为什么觉得写前端就不检查内存泄漏呢?
    atom
        13
    atom  
       2013-04-01 12:12:09 +08:00   1
    google有内存泄漏检测工具,https://code.google.com/p/leak-finder-for-Javascript/

    不过我们用一个比较土但是很实在的方法,每隔15分钟自动刷新一下页面,然后,世界就重新来过了。
    Frannk
        14
    Frannk  
       2013-04-01 13:08:11 +08:00   1
    @heroicYang 好像是的 但是没有泄漏意识的话 就不会经常使用 remove unbind off 之类的方法
    我觉得js前端泄露造成的问题不大 不会影响性能 但是事件的绑定管理不好(算是一种leak吧)的话 会对程序产生干扰
    breeswish
        15
    breeswish  
    OP
       2013-04-01 20:52:50 +08:00 via Android
    @Frannk 主要是考虑都在一个页面上加载的话一旦内容较多,多加载几次以后Chrome内存就很高了= = 再下去不科学……(不过也许还没到浏览器自己的gc周期= =)
    breeswish
        16
    breeswish  
    OP
       2013-04-01 21:01:43 +08:00 via Android
    @0x0001 感谢提醒;D 其实原本是为了取得更好的视觉效果 是个实验性分支~
    breeswish
        17
    breeswish  
    OP
       2013-04-01 21:03:38 +08:00 via Android
    @anhulife 谢谢提供参考~我会自己研究一下它们 :)
    heroicYang
        18
    heroicYang  
       2013-04-02 10:39:47 +08:00
    @anhulife 我们也基本上是这样的技术堆栈!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5611 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 03:03 PVG 11:03 LAX 20:03 JFK 23:03
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86