`
xhload3d
  • 浏览: 209186 次
社区版块
存档分类
最新评论

基于HTML5的WebGL应用内存泄露分析

阅读更多

上篇(http://www.hightopo.com/blog/194.html)我们通过定制了CPU和内存展示界面,体验了HT for Web通过定义矢量实现图形绘制与业务数据的代码解耦及绑定联动,这类案例后续文章还会继续以便大家掌握更多的矢量应用场景,本篇我们先切换个话题,谈谈模型-视图-事件之间的关系。

http://www.hightopo.com/guide/guide/core/beginners/examples/example_overview.html

图形组件设计架构上主要就是在规划Data模型,View视图和Event事件之间的关系,这些年业界逐渐将各种GUI设计模式提炼成理论归类,MVC、MVP和MVVM的主要大类常被统称为MV*,有很多文章进行各种设计模式的定义和比较,本篇不打算深入展开理论的讨论,不同图形组件设计架构都会有很多差异,持续发展的组件其实每时每刻都在进行着各种设计上的改进,相信有很多不错的组件已经创新出了更多新的更实用的设计模型,只不过还未被提炼到理论高度进行归类让世人知晓,因此过细去定义什么是P,什么是VM,哪个功能应该写在哪个部分才算合理我觉得是没太大意义的,只要不断改进产品,团队能更好维护扩展,用户易学易用就够了,理论高度留给Martin Fowler这类神级大师去定义。

提到Martin Fowler因为他的《GUI Architectures》和《Presentation Model》是我较早见到将MVC和MVP理清的文章,从实现角度其实几十年前苹果用于开发Mac OS X的Cocoa Bindings技术已采用了类似的设计,并且Objective-C语言的Key-Value Coding和Key-Value Observing机制,加上XCode工具的可视化支持,可以说多年来早已让众多开发者不知不觉在享受这些设计模型能带来的开发力。Java的Swing界面一直饱受诟病,但其实很早就有JGoodies这样优秀项目,Swing本就不算大众,了解JGoodies更是小众,而更少人了解JGoodies Binding这多年前就实现得非常不错的MVP架构封装,有兴趣的读者可看看JGoodies这篇06年的PPT《Desktop Patterns and Data Binding》

Adobe的Flex和微软的Silverlight/WPF本被业界寄予厚望,没想这哥俩如匆匆过客被老东家抛弃了,但他们还是推动了MVP和MVVM设计模式的普及,如今HTML5领域的KnockoutJS、Backbone.js、AngularJS、PureMVC、Ember.js等众多MV*框架如果雨后春笋般崛起,甚至需要有人专门维护个TodoMVC的网站来:Helping you select an MV* framework!

HT本身也是一套MV*的框架,但我们培训客户时很少过细讨论设计模式,在我看来好的组件封装应该不必让用户纠结于你的设计模式,用户几个月不用你的框架后,依然能快速上手不必有一个重写学习的过程,这是我们最求的理想框架,从这个角度说目前很少有图形框架能让我们满意,相信很多人有类似痛苦的经历,一段时间不用某套框架后,要用时完全忘记如何入手,Swing老手不看老代码不知如何对JTree和JTable添加数据,Flex老手一下子想不起来invalidateProperties,invalidateSize和 invalidateDisplayList这几个自定义组件必掌握函数的细节,SL/WPF老手想不起来定义一个DependencyProperty属性除了AffectsRenderer和AffectsMeasure还有多少要考虑的因素,上段提到的一堆新兴的HTML5界MV*框架,相信更少有人敢说熟练精通,你可能在某个项目中用了好几个月甚至一两年,但一段时间不用你很容易忘记,因此对喊出精通缺乏勇气了,我觉得这不是大家不聪明不勤奋,而是目前的这些框架真还没做到足够好,我们一直努力让HT朝我们觉得满意的方向发展,以后文章我再展开讨论HT如何设计让用户不健忘的API接口。

回到今天模型-视图-事件的话题,Data和View分离后必然需要有Event事件的监听和派发机制来建立起数据绑定,我控制欲比较强不是很喜欢AngularJS那种dirty checking的机制,有事件变化我希望马上被通知到,做我该做的处理,至于有人担心性能问题那是多虑了,图形组件发展这么多年已积累无数成熟技巧来规避事件的性能问题。

性能问题倒不用担心,毕竟这方面任务大部分情况都是交由框架实现者去考虑,但不需要用户深入了解框架的实现细节,并不意味着用户可以完全不关系基本架构脉络,框架应用者还是有必要了解模型-视图-事件之间的引用关联关系,否则容易出现内存泄露的问题,以前经历过一个客户团队设计的客户端框架,可管理所有界面的窗口,结果出现总是OOM的内存溢出,帮他们检查后发现,他们有个全局的WindowManager对象,在每个窗口创建时都会添加对窗口的引用,这样固然貌似很强大,全局都可以控制所有界面窗口,但因为绝大多数开发人员,不会在窗口关闭要销毁时主动去删除全局WindowManager对象的引用,进而导致了所有窗口都能被全局对象引用到而无法垃圾回收,因此框架的使用者还是有必要多框架的机制有所了解才能避免这类的内存泄露问题。

很多情况下内存泄露不是长期的运行也很难发觉,但对于HT的Graph3dView这种基于WebGL的3D组件问题尤为明显,因为大部分浏览器对单个页面能运行的WebGL上下文是有限制的,例如PC上的chrome或firefox也就运行十五六个,手机平板等移动终端会更受限,因此如果出现内存泄露老的上下文没关闭,超越上限时就会出现类型”Too many active WebGL contexts. Oldest context will be lost.”的异常。

以下我对《HT入门手册》的第一个例子做个扩展,对工具条增加了如下代码逻辑的三个按钮,第一个按钮一下子创建了20个新的Tab页,每个Tab页包含一个Graph3dView组件,另外两个按钮实现删除部分页签的功能。

{
    label: 'Create 20',
    action: function(){                             
        for(var i=0;i<20;i++){  
            var tab = new ht.Tab();
            tab.setName('tab-'+i);
            tab.setClosable(true);                                
            tabView.getTabModel().add(tab);    
            var g3d = new ht.graph3d.Graph3dView(dataModel);
            g3d.name = 'g3d-' + i;
            window['g3d-' + i] = g3d;
            tab.setView(g3d);
        }                            
    }
},  
{
    label: 'Destroy 5',
    action: function(){           
        var emptyModel = new ht.DataModel();
        tabView.remove('tab-5');
        window['g3d-5'].setDataModel(emptyModel);
        delete window['g3d-5'];  
        this.disabled = true;
    }
},
{
    label: 'Destroy 6-10',
    action: function(){    
        for(var i=6; i<=10; i++){
            tabView.remove('tab-' + i);
            var emptyModel = new ht.DataModel();
            window['g3d-' + i].setDataModel(emptyModel);
            delete window['g3d-' + i];                                
        } 
        this.disabled = true;
    }
}

 

点击创建20个页签的按钮分别打开页签之后系统的内存对象引用关系如下图所示:

Screen Shot 2014-08-15 at 9.46.17 PM

因为dataModel作为全局对象被window应用着,而且其他新创建的页签中的Graph3dView都绑定了该数据模型,框架使用者应该了解,各种组件都对dataModel数据模型添加了事件监听,其实数据模型并不知道各种View的存在,数据模型仅遵循有数据变化后将事件正确的派发给所有消费者,而这20个Graph3dView就是其中的消费者,而Graph3dView中每个有都有一个WebGL的context上下文,因而形成了一条从全局window到dataModel数据模型,再到Graph3dView组件,最后到WebGL上下文的引用关系网,这样自然如果我们不主动断开这个关系,哪怕Tab页签被关闭销毁,Graph3dView依然还会存在系统内存的问题(这个例子我们为了测试方便其实还在window上直接引用了Tab和Graph3dView对象)。

Screen Shot 2014-08-15 at 10.12.59 PM
http://v.youku.com/v_show/id_XNzU2MzYzODA4.html

因此由以上视频你会发现在chrome下当点击到第16个包含Graph3dView的页签后就出现了”Too many active WebGL contexts. Oldest context will be lost.”的异常,在WebGL中可通过对Canvas添加webglcontextlost的事件监听可判断自己的上下文被销毁了,并可通过添加webglcontextrestored的事件监听在浏览器资源足够时重新进行恢复。

在我们这个案例中要让系统资源恢复,我们必须让过多的Tab页签中的Graph3dView被彻底回收,因此工具条上的另外两个按钮从代码逻辑可知,我们将Graph3dView设置了一个新的空得DataModel数据模型,使其断开了和全局window.dataModel的引用,当然Tab页签也得删除,从以上视频中也可以看得出当我们销毁了部分Tab页签后就能得到webglcontextrestored的事件恢复,因此第一个”HT for 3D Web”的页签经历了webglcontextlost和webglcontextrestored的过程。

启动初始化时只有”HT for 3D Web”的第一个页签,因此通过Chrome的Debug Profiles可查看到ht.graph3d.Graph3dView的Objects Count项只有1,通过Profiles的Retainers我们还可以清楚的掌握目前达到那些对象引用了Graph3dView对象:

Screen Shot 2014-08-15 at 10.11.31 PM

当点击构建20个页签按钮后,Profiles能看到Objects Count为21:

Screen Shot 2014-08-15 at 10.11.50 PM

当我们点击两个删除按钮销毁6个Tab页签后发现,Objects Count下降到了15:

Screen Shot 2014-08-15 at 10.12.23 PM

最后可以发现第一个HT for 3D Web的页签浴火重生了

Screen Shot 2014-08-15 at 10.13.47 PM

这个案例只是为了测试方便因此将dataModel对象作为全局变量,所以引发了一些列内存泄露的资源不足问题,一般项目应用中不用的组件不需要考虑这么复杂,例如还需要断开dataModel引用这些步骤,常规应用场景中例如一个对话框打开后,一般数据模型和视图组件都在这个对话框范围内相互引用,只要确保不出现上文提到的有全局引用能影响这个对话框内的某个对象,那么你在使用完该对话框后不需要做任何处理,那一堆的对象哪怕他们之间引用再复杂甚至互相应用,反正没有全局对象能够再引用到他们,他们统统都会被销毁。

http://www.hightopo.com/guide/guide/core/beginners/examples/example_overview.html

总结下本篇的两个观点:

1、再好的封装设计也需要使用者掌握基本的架构脉络,就像再好的车你也得学会开学会基本的保养,什么都不学的话,再好的框架也会像好车一样被你开坏

2、不要惧怕MV*的事件和引用关系,理清事件机制和对象引用关系后,你可以精确掌控任何时刻的任何内部细节,这点主要针对设计框架者而言,使用者应该大胆的拥抱MV*的框架,性能和各种潜在的内存问题放心的交给框架去解决

 

5
6
分享到:
评论

相关推荐

    webgl-debug.js

    "webgl-debug.js"是一个专门针对WebGL编程的调试库,它通常用于帮助开发者更好地理解和解决问题,提高WebGL应用程序的性能和稳定性。 在WebGL编程中,"webgl-debug.js"提供了以下关键功能和知识点: 1. 错误检测与...

    Unity通用WebGL模板Universal WebGL Template 1.2.1

    此外,WebGL应用可能需要优化以应对可能的内存和性能限制。 总之,Unity通用WebGL模板1.2.1为开发者提供了一个便捷的途径,将Unity项目无缝移植到Web上。它简化了WebGL项目的构建过程,同时考虑到了性能、兼容性和...

    webGl技术实现的H5游戏-飞机

    这个“webGl技术实现的H5游戏-飞机”项目,显然是一款基于WebGL和HTML5开发的飞行射击游戏,展示了WebGL在创建交互式、高性能的H5游戏方面的潜力。 首先,我们要理解WebGL的基础。它是一种JavaScript API,遵循...

    Unity3D如何导出为webGL--教程.zip

    WebGL应用程序需要注意安全问题,比如防止XSS攻击和内存泄漏。合理设置Unity的CSP(Content Security Policy)和遵守最佳实践。 9. **WebGL的局限性** 相比原生桌面或移动应用,WebGL可能在性能和功能上有一定...

    webGL开发指南文档

    - **内存管理**:有效利用和释放资源,避免内存泄漏。 9. **WebGL框架与库** - **Three.js**:最流行的WebGL库,提供了丰富的功能和简便的API,降低了3D编程的复杂性。 - ** Babylon.js** 和 **PlayCanvas**:...

    webgl图文教程

    它是HTML5技术的重要组成部分,特别是在构建交互式、动态和视觉丰富的Web应用程序时。这个“webgl图文教程”集合包含了离线版本的教程资源,方便用户在没有网络连接的情况下也能学习和研究WebGL。 WebGL的核心是...

    WebGL自适应.rar

    5. **性能优化**: WebGL应用程序可能会受到浏览器性能限制,因此了解如何优化代码、减少Draw Call、使用LOD(Level of Detail)技术以及利用延迟渲染等策略对提升性能至关重要。 6. **资源加载管理**: 在WebGL项目...

    基于WebGL和glTF的快速轻量级JavaScript游戏引擎.zip

    1. **WebGL**: WebGL 是一种基于OpenGL ES 2.0的JavaScript API,用于在HTML5 canvas元素上进行交互式2D和3D图形渲染。通过WebGL,开发者可以直接在浏览器中构建复杂的3D场景,实现动态渲染和交互,使得网页游戏的...

    webGL编程指南.pdf+代码

    WebGL是一种基于OpenGL标准的JavaScript API,用于在任何兼容的Web浏览器中实现硬件加速的2D和3D图形渲染。这个“WebGL编程指南”很可能提供了深入的介绍,帮助读者理解如何利用WebGL来创建交互式的网页图形。下面将...

    hyperKitGL:hyperKitGL是kitGL的html5 webgl部分

    5. **资源管理**:提供有效的资源加载和管理机制,确保内存占用合理,避免内存泄漏。 6. **社区支持**:作为开源项目,hyperKitGL有活跃的开发者社区,提供持续的更新和问题解答。 **使用hyperKitGL开发** 在`...

    html5全屏3D效果圣诞雪花飘洒效果 v1.0

    开发者可能使用JavaScript或者基于HTML5的WebGL库(如Three.js)来处理3D渲染。JavaScript代码会生成大量表示雪花的粒子,并控制它们的运动状态,包括速度、方向和旋转。为了实现鼠标跟随效果,还需要监听`mousemove...

    基于TypeScript的HTML5游戏开发.pdf

    在现代Web开发中,HTML5游戏开发已经成为一个热门领域,结合强类型编程语言TypeScript,开发者可以构建出更健壮、可维护性更强的游戏应用。本篇内容将深入探讨如何利用TypeScript进行高效的HTML5游戏开发。 首先,...

    cocos2d-html5-v2.2.3

    同时,可能也对内存管理进行了优化,减少了内存泄漏的可能性,确保了游戏在长时间运行时的稳定性。 除此之外,cocos2d-html5-v2.2.3可能还包括对开发者工具的升级,如Cocos Creator,这是一个集成的开发环境,提供...

    HTML5_Canvas开发详解(第2版)

    书中可能包含关于减少重绘区域、缓存图形、避免内存泄漏等提高Canvas性能的策略。 6. **高级特性**:除了基础功能,Canvas还支持WebGL,这是一种在Canvas上进行3D图形绘制的API。虽然这不是Canvas的核心部分,但...

    unitywebgl

    5. 网络传输:由于WebGL应用通常包含大量数据,所以需要考虑如何有效地传输这些数据,例如使用分块加载、压缩和缓存策略。 6. 安全性:WebGL应用运行在沙盒环境中,有特定的安全限制。开发者需要了解这些限制,如...

    HTML53d乒乓球小游戏

    7. **性能优化**:考虑到浏览器环境的限制,优化代码以减少重绘和重排,避免内存泄漏,是保证游戏运行流畅的重要环节。 8. **音效集成**:为了增强用户体验,游戏可能还集成了音频元素,如击球声、得分音效等,这...

    450多款H5小游戏源码.zip

    8. **性能优化**:学习如何优化代码以提高游戏性能,包括减少重绘、合理使用缓存、避免内存泄漏等。 通过深度学习和实践这些源码,你将能够提升自己的H5游戏开发能力,无论是对游戏设计的理解,还是技术应用的熟练...

    H5小游戏源码 逗比测试.zip

    H5小游戏源码是指基于HTML5、CSS3和JavaScript等技术编写的轻量级游戏的原始代码。HTML5作为现代网页开发的核心标准,提供了更强大的多媒体支持,如Canvas画布、Web Audio API、WebGL等,使得在浏览器中创建动态和...

    Android应用源码之chromeview-master_应用.zip

    - **更丰富的Web API**: 支持HTML5、CSS3等现代Web标准,以及WebGL、WebRTC等高级特性。 - **隐私控制**: 提供更细粒度的隐私设置,如Cookie管理。 - **崩溃隔离**: 由于其独立于系统WebView,ChromeView能更好地...

    H5小游戏源码 宠物大营救.zip

    【宠物大营救】是一款基于H5技术开发的轻量级小游戏,它的源码提供了深入理解HTML5游戏开发的宝贵资源。H5小游戏源码是使用HTML5、CSS3和JavaScript等前端技术构建的,这类游戏可以在网页上直接运行,无需用户安装...

Global site tag (gtag.js) - Google Analytics