My Little World

一点V8引擎知识

1.V8占用操作系统内存很少,为什么?
类似于体育场办演唱会,演唱会结束后,清完垃圾才能开下一场,
如果场子小,2小时搞定,如果场子大,人多产生垃圾多,清理时间就会变长
在64位操作系统中占用1.4G,32位操作系统中占0.7G
表面原因是JS设计之初是用于给浏览器跑脚本,脚本跑完一次就结束了,不需要长期运行占用内存,以上这些空间足够
实际原因是垃圾回收机制在进行时,会停掉正在运行的整个程序,回收结束后继续运行,
而一次小型垃圾回收几MB会消耗50ms,程序运行就会停止50ms
如果说给的内存太大,那么跑的程序肯定会多来,产生的垃圾也会随之增多,回收时间就变长,结果就会导致程序运行间歇性执行
这肯定是不能让人接受的

2.垃圾回收算法
V8引擎将所占内存分成两块,
一个叫新生代空间,用于存放生命周期较短的变量,比如一个函数里的局部变量,函数运行完即释放
一个叫老生代空间,占引擎内存的90%以上,用于存放生命周期较长的变量,比如全局变量,从程序运行开始就存在

新生代空间垃圾回收算法就是复制
新生代空间又分两部分,一个叫from一个叫to
回收时会将from中活着的变量复制到TO空间,然后将from空间清空,再将from和to空间内容对调
原理是用空间换取时间,有一半新生代空间处于空置状态,而对调减少了清理磁盘空间的过程,从而节省了时间

老生代垃圾回收算法 就是标记删除整理
标记死掉的没有生命周期的变量,边删除标记的变量,边整理碎片(内存空间),将删除导致的磁盘碎片用活着的变量通过移动补齐

3.新生代晋升老生代条件
新生代空间的变量经历过一次复制,即经过一次垃圾回收,而且TO空间已经使用了25%,那么这个变量就会被安排到老生代空间

4.利用node查看内存情况
cmd 敲击node命令
使用process.memoryUsage()查看,返回包含以下属性对象
rss:V8占用的总内存(占用比使用会多一些)
heapTotal:当前程序被分配到的总内存
heapUsed:当前程序使用的内存
external:调用的部分C++内存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 function getMB(){
var mem = process.memoryUsage()
var format = function(bytes){
return (bytes/1024/1024).toFixed(2)+'MB'
}
console.log('heapTotal:'+format(mem.heapTotal)+' heapUsed:'+format(mem.heapUsed))
}
let a = ()=>{
let b = new Array(1024*1024)
return b
}
let b = a()
let d = a()
let e = a()
let f = a()
let g = a()
// let h = a()
// let i = a()
// let j = a()
// let k = a()
// let l = a()
// let m = a()
// let n = a()
// let o = a()
// let p = a()
// let q = a()
getMB()

在cmd中转到文件所在目录,node 包含以上代码的js文件,即可打印内存使用情况

5.优化内存技巧
尽量不要定义全局变量
全局变量记得销毁掉
用匿名自执行函数变全局为局部
尽量避免闭包

在使用立即执行函数实现闭包时,
函数内代码,为同步操作时,占用内存与不使用闭包相同
但如果包含异步操作,则函数内用到的外界变量会一直处于被引用状态
得不到释放从而导致内存增加
解决:使用完释放;避免使用闭包

6.导致内存泄露
滥用缓存

js中导致内存泄露的常见场景
闭包函数
全局变量
对象属性循环使用
Dom节点删除时未解绑事件
Map和Set数据类型的数据属性直接删除,导致指向的数据没有被删除