JavaScript内存管理
内存管理介绍:
- 内存:由可读写单元组成,表示一片可操作空间。
- 管理:认为地去操作一片空间的申请、使用和释放。
- 内存管理:开发者主动申请空间、使用空间、释放空间。
JavaScript中的垃圾回收
JavaScript中的垃圾
- JavaScript中内存管理是自动的。
- 对象不再被引用时是垃圾。
- 对象不能从根上访问到时是垃圾。
JavaScript中的可达对象
- 可以访问到的对象就是可达对象(引用、作用域链)。
- 可达的标准就是从根出发是否能够被找到。
- JavaScript中的跟就可以理解为是全局变量对象。
可达对象图示:
如上图所示中对象皆为可达对象。而若将o1和Prev两条作用域链断开,则objec1将不再是可达对象,形成垃圾。
GC算法介绍
GC定义与作用:
GC就是垃圾回收机制的缩写。GC可以找到内存中的垃圾,并释放和回收空间。
常见GC算法
- 引用计数
- 标记清除
- 标记整理
- 分代回收
引用计数算法实现原理及优缺点
引用计数算法:
核心思想:设置引用数,判断当前引用数是否为0
引用计数器。
引用关系改变时修改引用数字。
引用数字为0时立即回收。
引用计数算法优点:
发现垃圾时立即回收。最大限度减少程序暂停。
引用计数算法缺点:
无法回收循环引用的对象。时间开销大。
标记清除法实现原理及优缺点
标记清除法:
核心思想:分标记和清除两个阶段完成。
遍历所有对象寻找标记活动对象。
遍历所有活动对象清除没有标记对象。
回收相应的空间。
标记清除法优点:
在找到第一层可达对象后,GC算法会用递归的方式继续找到可达对象,故可以回收循环引用的对象。
标记清除法缺点:
容易产生碎片化空间,造成空间的浪费。且不会立即回收垃圾对象。
标记整理法
标记整理法可以看做是标记清除的增强。在标记阶段的操作和标记清除一致,清理阶段会先执行整理,移动对象位置,减少碎片化空间,但是回收效率慢。
V8垃圾回收策略
- 采用分代回收的思想。
- 内存分为新生代、老生代。
- 针对不同对象采用不同算法。
V8垃圾回收策略图示
V8中常用的GC算法
- 分代回收
- 空间复制
- 标记清除
- 标记整理
- 标记增量
V8如何回收新生代对象
V8内存分配:
V8内存空间一分为二,小空间用于存储新生代对象(32M|16M) /*对应64位系统和32位系统*/。新生代指的是存活时间较短的对象。
新生代对象回收实现:
- 回收过程采用复制算法+标记整理。
- 新生代内存区分为两个等大小空间。
- 使用空间为From,空闲空间为To,
- 活动对象存储一From空间。
- 标记整理后将活动对象拷贝至To。
- From与To交换空间完成释放。
回收细节补充说明:
拷贝过程中可能出现晋升(晋升就是讲新生代对象移动到老生代),一轮GC还存活的新生代需要晋升。To空间的使用率不超过25%,以防影响拷贝交换。
V8如何回收老生代对象
老生代对象说明:
老生代对象存放在右侧老生代区域,64位操作系统为1.4G,32位操作系统为700M。老生代对象就是指存活时间较长的对象。
老生代对象回收实现:
- 主要采用标记清除、标记整理、标记增量法。
- 首先使用标记清除完成垃圾空间的回收。
- 采用标记整理进行空间优化。
- 采用增量标记进行效率优化。
细节对比:
新生代区域垃圾回收使用空间换空间。
老生代区域垃圾回收不适合复制算法。
标记增量如何优化垃圾回收:
标记增量可以将当前一整段的垃圾操作,拆分成多个小步骤组合的去完成,这样做的好处主要可以实现垃圾回收与程序执行交替的完成,而不会阻塞进程。
V8总结
- V8是一款主流的JavaScript执行引擎。
- V8内存设置上限。
- V8采用基于分代回收思想实现垃圾回收
- V8内存分为新生代和老生代。