1.作为前端开发,为什么要关注内存?
- 防止页面占用内存过大,引起客户端卡顿,甚至无响应
- Node使用的也是v8引擎,内存对于后端服务的性能至关重要,因为服务的持久性,后端更容易造成内存溢出
2.V8引擎的内存回收机制

内存大小:
- 总内存和操作系统有关 64位 为1.4G,32位 为0.7G
- 64位下新生代的空间为64MB,老生带为1400MB
- 32位下新生代的空间为16MB,老生代为700MB
提问:为什么v8引擎对自己的内存大小进行限制呢?
回答:
- js设计之初是为了浏览器,前端的特点-不持久化,执行一遍就全部会回收了,1.4完全足够用了
- js回收内存的时候,会暂停执行,回收一次100MB,大概需要6ms,设计太大,会造成明显卡顿
3.垃圾回收算法:
- 新生代:存放一些比较小而且存放时间比较少的变量,最开始的时候,新生代的变两个会全部放在(From)这个空间内,当我们 时,新生代内存需要回收时,会把还活着的变量复制到(To)空间内,把(From)空间内的内容全部清空,这样做的目的是用空间来换时间,总是有一半的空间是空置的
- 老生代:不能采用新生代的算法,因为老生代的空间过大,会造成大量内存空间的浪费。它将会使用标记删除整理的算法。如下图所示,假设黑色的都是被标记需要删除的变量,这时,V8引擎会将黑色的进行清空,将白色可用的内存块往前移,这样做的目的是让可用内存空间变大,防止数组在可用内存中存放不了(因为数组必须是连续内存空间!)

4.新生代如何晋升到老生代:

5.利用node来查看内存使用情况:
function getMe(){
var mem = process.memoryUsage()
var format = (bytes) => {
return (bytes/1024/1024).toFixed(2) + 'MB'
}
console.log('Process: heapTotal ' + format(mem.heapTotal) +
' heapUsed ' + format(mem.heapUsed) + ' rss ' + format(mem.rss))
}变量处理
- 内存主要就是存储变量等数据的
- 局部变量当程序执行结束,且没有引用的时候就会随着消失
- 全局对象会始终存活到程序运行结束
体验一下撑爆v8引擎,代码如下:
var size = 20*1024*1024
var arr = new Array(size)
var arr1 = new Array(size)
var arr2 = new Array(size)
var arr3 = new Array(size)
var arr4 = new Array(size)
var arr5 = new Array(size)
var arr6 = new Array(size)
var arr7 = new Array(size)
var arr8 = new Array(size)
var arr9 = new Array(size)
var arr10 = new Array(size)
var arr11 = new Array(size)
var arr12 = new Array(size)
var arr13 = new Array(size)
var arr14 = new Array(size)直接在node中运行该代码,v8引擎就会报错,内存溢出
为了看的更加仔细,可以在每个arr后面都调用getMe()方法,查看每次声明之后的内存使用情况
体验一下v8引擎内存回收带来的卡顿,代码如下:
var size = 20*1024*1024
var a = []
function b() {
var arr1 = new Array(size)
var arr2 = new Array(size)
var arr3 = new Array(size)
var arr4 = new Array(size)
var arr5 = new Array(size)
}
b()
for(var i = 0; i < 13; i++) {
a.push(new Array(size))
getMe()
}
直接在node运行该代码,可以 看到:
在红框标注的地方,就进行了内存回收,会感觉到一丝丝卡顿,因为v8回收内存的时候,会暂停执行,回收一次100MB,大概需要6ms
6.如何注意内存的使用
优化内存的技巧:
- 尽量不要定义全局变量
- 全局变量记得销毁掉(怎么删除?直接将全局变量赋值为
undefined或者null,扩展:null是一个保留字,undefined是一个特殊一点的变量) - 用匿名函数自调将全局变量变为局部变量
- 尽量避免闭包(错误的理论,只有在外部引用的时候,才会有可能造成内存泄漏)
防止内存泄漏:
- 滥用缓存(在写服务端代码时,尽量不要使用js变量来缓存,可以使用redis等来代替。如果一定要用js变量缓存,则需要加锁,在增加缓存之前,判断一下该变量的长度是否超过一定值,超多的话,就把第一个缓存进来的数据清空,遵循先进先出原则,这样做会导致缓存不完整,但是至少不会让服务器宕机)
- 大内存量操作(node操作文件时比如:
fs.readFile,该api会一次性读取文件到buffer,如果文件非常大,就会造成内存泄漏,所以类似这样的操作,需要优化成:createReadStream().pipe(write),创建读取文件流,一点一点读取文件内容;浏览器上传大文件时,也会存在内存泄漏的问题,这个时候就要用到切片上传,使用file.slice())