内存泄漏
内存泄漏:任何一个程序的运行都需要分配内存空间,而对于一个页面来说,如果一些不再需要使用的内存没有得到及时释放,我们称这种现象为内存泄漏。一次内存泄漏似乎不会有太大的影响,但内存泄漏堆积会造成内存溢出,内存溢出,简单来说就是我们所需要使用的内存空间大于可用内存,此时我们的程序就会出现内存溢出错误。
为什么要管理内存
(1)减少浏览器的负担:内存过大会让浏览器压力过大,导致浏览器卡顿
(2)Node端:内存如果不够,服务就会中断,而nodejs开启的服务,如果不管理内存,就会中断。
内存的数据存储
数据类型:
原始数据类型:字符串(String)、数字(Number)、布尔(Boolean)、空对象(Null)、未定义(Undefined)、Symbol。变量存放在栈(先进后出),按值引用;
引用数据类型:方法(function)、对象(Object)、数组(Array);存放在堆中,按引用访问,栈中的变量指向堆的地址。
JS是不允许直接访问堆内存的,因此我们也无法直接操作对象的堆内存空间。我们在操作对象时,实际上是在操作对象的引用而不是实际的对象。因此,引用类型的值都是按引用访问的。
如var a={name:'buding'}; 对象{name:'buding'}存放在堆中,栈中的变量a指向堆的地址。
JavaScript的垃圾回收机制
垃圾回收机制:
找出那些不再继续使用的变量,然后释放其所占用的内存,垃圾回收器会按照固定的时间间隔周期性地执行这一操作。
javaScript使用垃圾回收机制来自动管理内存,垃圾回收是一把双刃剑:
优势:可以大幅简化程序的内存管理代码,降低程序员的负担,减少因长时间运转而带来的内存泄露问题。
不足:意味着程序员将无法掌控内存。JavaScript没有暴露任何垃圾回收器的接口。我们无法强迫其进行垃圾回收,更无法干预内存管理。
垃圾收集方式:(1)标记清除
(2)引用计数
v8内存的管理
v8内存大小:64位下是1.4G, 32位下700MB,但是根据浏览器不同,有些许扩容。Node情况下会有一些C++内存扩容。
V8采用了一种分代回收的策略,将内存分为两个生代:新生代和老生代。
垃圾回收(GC)算法基于Generational Collection ,内存被划分为两种,分别称为新生代Young Generation(YG) 和老生代Old Generation(OG)
新生代:短时间存活的新变量会存在新生代种中,新生代的内存量极小,64位下大概是32MB。分配和回收快而频繁,一般存在的时间很短,所以称为Young
老生代:生存时间比较长的变量,会转存到老生代,老生代占据了几乎所有内存。64位下大概是1400MB。OG中分配和回收慢而少发生,所以称为Old。老生代内存空间是一个连续的结构。
新生代的回收算法,可以检署为复制-清空,把存活者的变量复制到to空间,然后把from空间清空,然后对调from和to。这样可以提升回收速度,典型的牺牲空间换时间。
老生代回收分为三步:①标记已死变量②清除已死变量③整理磁盘。
参考文章:https://segmentfault.com/a/1190000013304880
新生代和老生代如何转化:①新生代发现本次复制后,会占用超过25%的to空间②这个对象已经经历过一次回收。
触发回收:①执行完一次代码;
②内存不够的时候
可以回收的变量:
①全局变量,直到程序执行完毕才会回收;②普通变量,当失去引用时回收
优化内存
内存检测:浏览器端【window.performance.memory】、Node端【process.memoryUsage()】
优化建议:(1)尽量不要定义全局,定义了及时手动释放(释放方法定义变量为undefined)(2)注意闭包,闭包主要不要让其存在无限增长的情况,无限增长会导致内存溢出,可以限制增大的长度。
闭包
局部变量无法共享和长久的保存,而全局变量可能造成变量污染,所以我们希望有一种机制既可以长久的保存变量又不会造成全局污染。闭包就实现了上述的功能,闭包使得函数内部的变量在函数执行完后, 仍然存活在内存中(延长了局部变量的生命周期),让函数外部可以操作(读写)到函数内部的数据(变量/函数)。
闭包三个特性:
(1)函数嵌套函数
(2)函数内部可以引用外部的参数和变量
(3)参数和变量不会被垃圾回收机制回收
JavaScript---闭包技术 迈向高级JS程序员的必经之路_maidu_xbd的博客-CSDN博客
Node端一些特殊点:(1)Node可以手动触发垃圾回收- global.gc(2)Node端可以设置内存【node --max-old-space-size=1700 test.js】和【node --max-new-space-size=1024 test.js】
注意:传统的浏览器端,js无法手动触发垃圾回收,只能依赖自动进行。
v8为什么设计为1.4g:(1)1.4g对于浏览器脚本来说够用(2)回收的时候是阻塞式的,也就是进行垃圾回收的时候会中断代码的执行。如果内存很大,等待垃圾回收时会造成阻塞。