TAT.uxu 浅谈 Web 应用的内存优化
In 未分类 on 2019年07月31日 by view: 5,886
0

随着 Web 应用复杂程度越来越高,以及 NodeJS 大规模投入生产环境,许多 Web 应用都会长时间运行, JavaScript 的内存管理显得更为重要。

JavaScript 具备自动回收垃圾的机制, 执行环境会负责管理代码在执行环境过程中使用的内存,将某些不再被使用的的变量所占用的内存释放掉,正因如此,大多数情况我们在前端开发的时候,并不是那么关注我们的页面用了多少内存,是否合理,需不需要优化。

JavaScript 基础中有很多重要的知识点是和内存相关的,比如深拷贝和浅拷贝、闭包、原型、引用数据类型和引用传递等。

当然,关于 JS 的内存空间和内存相关的知识已经有很多专业的文章解释的很详细了,这里就不再赘述了。

比如关于 JS 内存空间的知识可以看看:内存空间详细图解

关于内存周期和垃圾回收的知识可以阅读参考 MDN 的文章,其他文章无外乎也是根据这个来介绍的:Memory_Management

关于 JavaScript 内存泄漏也可以看一下阮一峰老师的文章 JavaScript 内存泄漏教程

在 Web 应用开发中,我们应该注意:

1. 避免没有必要全局变量的使用

前端开发者都知道,在局部作用域中,当函数执行完毕,局部变量也就没有存在的必要了,它很容易被垃圾回收器回收,当使用全局变量定义值时,垃圾回收器,很难判断全局变量需要什么时候释放内存空间,因此是不会去对其进行回收销毁的。而该变量会一直存在老生代堆内存中,直到页面被关闭。

另外一种意外情况是;

我们可以在 JS 文件的开头通过添加"use strict" 开启严格的解析模式,来避免一些意外创建的全局变量。

2. 及时解除引用

如果必须要一个全局变量来存储大量数据,那么请确保在用完之后将其赋值为 null。

delete 操作符用于删对象的某个属性;如果没有指向这个属性的引用,那它最终会释放。

但注意的一点是,尽量不要在需要密集运算的函数中去使用 delete,这很可能会引发浏览器在不恰当的时候的 GC,和其他语言一样,JavaScript 的 GC 策略无法避免 GC 时停止响应其他操作,而 JavaScript 的 GC 在 50ms 甚至以上,对普通应用还好,如果是对于操作频繁的 Web 应用或者游戏来说,就比价烦恼了。

有时候我们虽然用 removeChild 移除了 button,但是还在 node 对象里保存着 #button 的引用,DOM 元素还在内存里面,需要及时解除引用。

3. 减少对象的创建

垃圾回收周期性运行,如果分配的内存非常多,或者新建很很多实例的话,那么回收工作也会很辛苦。

尽量避免在经常调用的方法中循环使用 new 对象,而且还要花时间对这些对象进行垃圾回收和处理。

设计模式中的享元模式就是为了减少对象的多次创建而来的。在我们可以控制的范围内,最大限度的重用对象。

4. 内存不是缓存

缓存在需求开发中举足轻重,但是很多时候我们会把许多大数据缓存在内存中,导致我们的内存占用始终处于高位,内存对任何程序开发都是寸土寸金 的,若果不是很重要的资源,请不要直接放在内存中,或者制定过期机制,自动销毁过期缓存。

5. 避免复杂的递归调用;

通常情况下,简单的递归调用还不至于导致堆栈溢出,但遇到复杂且每次调用需要 在栈里存储大量信息的时候,成千上万个此类空间累积起来,很容易就超过了栈空间。

6. 合理使用的 IndexedDB

其实这个是和 JS 关系不是很大,但是对于 Web 应用的影响却十分重要,曾经我遇到过一个用户案例,由于长时间的本地数据写入,和一些上报日志没有被及时清除,导致用户的浏览器中对应域名下的 IndexedDB 存储高达 12GB,浏览器在访问对应域名的时候,也可以初始化 IndexedDB 和读取本地存储的数据,而面对如此庞大的数据,浏览器内存暴涨,最后崩溃,避免过度依赖 IndexedDB,无脑写入数据而不做定期清理。

总结

这篇分享主要总结了我们在 Web 应用,可能会遇到的一些情况和注意的事情。

很多时候只要我们在编码的时候多加注意,可以避免很多问题。

原创文章转载请注明:

转载自AlloyTeam:http://www.alloyteam.com/2019/07/13858/

发表评论