我们在使用Javascript编写WebApps时,一般不会考虑对象的生命周期,也不会太在意内存“泄漏”的问题。 JS引擎的垃圾回收机制可以很好的运行。基本上,它很少发生。发生浏览器崩溃。但是在web上展示大型3D模型时,内存/显存是非常紧张的资源,需要综合考虑模型数据组织、任务调度、资源管理、浏览器兼容性等问题。本文针对基于 WebGL 的 3D 应用开发中导致浏览器崩溃的几种情况进行分析并提供解决方案。
异步请求太多
浏览器对并发异步请求有限制。如果程序无法处理,“同时”发送数百个请求可能会使浏览器崩溃。
解决方案:
使用请求队列:将需要多次请求的数据重新组织起来,在一个或多个请求中完成。如果需要多次请求(成百上千次),可以对请求进行排队,使用多个异步请求队列来加载数据。
并发异步请求资源死锁
如果多个异步请求同时请求一个资源,可能会导致浏览器死锁。死锁的结果是浏览器崩溃。默认情况下,浏览器是启用缓存的,当从缓存中读取数据时浏览器会锁定。
解决方案:
在组织异步请求队列时上网老页面崩溃,将相同的资源放在同一个队列中,而不是放在不同的队列中。
GPU 进程崩溃
Chrome 是多进程架构,每个 Tab 都会启用一个单独的进程来处理页面。但是所有进程都将共享一个 GPU 进程。那么问题来了,如果打开多个WebGL应用页面,每个页面占用一定的GPU资源,GPU进程的总内存很容易超过1.5G,结果就是GPU进程崩溃。对于 64 位 Chrome,情况略有改善,但取决于本机 GPU 内存大小。在实践中使用 WebGL 显示大型模型很容易使 GPU 进程不堪重负。
解决方案:
优化网格数据
网格简化
网格共享
使用对象池
限制同时绘制的对象数量
JS 对象过多导致崩溃
在上图中的浏览器管理器中,可以看到多个内存:内存、GPU内存、Javascript内存。 Javascript内存是JS对象占用的内存,这部分内存被JS垃圾回收。
Javascript代码和垃圾回收运行在同一个线程环境中,垃圾回收时上网老页面崩溃,js代码不会被执行。如果js对象过多(占用内存过多),垃圾回收的过程也会变长。所以 Chrome 简单粗暴地限制了 Javascript 的内存使用,在 x64 下最高可达 ~1.4G。
解决方案:
优化的数据结构
添加动态数据管理机制。
JS 代码超时
如果JS运行时间过长,超过一定时间,浏览器会弹出对话框,让用户选择是否结束。相同的代码在 chrome 中运行良好,但在 Firefox 中可能会变得无响应。
解决方案:
设计分步执行的耗时算法,并使用requestAnimationFrame模拟多线程。
总结
相对于桌面应用开发,浏览器是一个资源受限的环境:JS执行效率、内存、线程等。对于大型的Web应用,我们往往需要平衡性能和资源。