本教程操作环境:windows7系统、javascript1.8.5版、dell g3电脑。
javascript 中的垃圾回收机制(gc)垃圾回收相关概念
① 什么是垃圾
没有被使用(引用)的对象就是垃圾。
② 什么是垃圾回收
没有被引用的对象被销毁,内存被释放,就是垃圾回收。
c、c++ 等编程语言需要手动垃圾回收。
java、javascript、php、python 等语言自动垃圾回收。
js中拥有自动的垃圾回收机制,会自动将这些垃圾对象从内存中销毁,我们不需要也不能进行垃圾回收的操作。我们需要做的只是要将不再使用的对象设置为 null 即可。
为什么需要垃圾回收在c / c++中,跟踪内存的使用和管理内存对开发者来说是很大的负担javascript是使用垃圾回收机制的语言,也就是说执行环境负责在代码执行时管理内存,帮开发者卸下了这个负担通过自动内存管理实现内存的分配和资源的回收基本思路很简单,确定哪个变量不会再被使用了,把它的内存空间释放这个过程是周期性的,意思是这个垃圾回收程序每隔一段时间就会运行一次像js中的对象、字符串、对象的内存是不固定的,只有真正用到的时候才会动态分配内存这些内存需在不使用后进行释放以便再次使用,否则在计算机可用内存耗尽后造成崩溃浏览器发展史上的垃圾回收法主要有引用计数法标记清除法引用计数法
思路
变量只是对值进行引用当变量引用该值时,引用次数+1当该变量的引用被覆盖或者清除时,引用次数-1当引用次数为0时,就可以安全地释放这块内存。let arr = [1, 0, 1] // [1, 0, 1]这块内存被arr引用 引用次数为1arr = [0, 1, 0] // [1, 0, 1]的内存引用次数为0被释放 // [0, 1, 0]的内存被arr引用 引用次数为1const tmp = arr // [0, 1, 0]的内存被tmp引用 引用次数为2
循环引用问题
netscape navigator 3.0 采用
在这个例子中,objecta和objectb的属性分别相互引用造成这个函数执行后,object被引用的次数不会变成0,影响了正常的gc。如果执行多次,将造成严重的内存泄漏。而标记清除法则不会出现这个问题。function example(){ let objecta = new object(); let objectb = new object(); objecta.p = objectb; objectb.p = objecta; }example();
解决方法:在函数结束时将其指向nullobjecta = null;objectb = null;
标记清除法为了解决循环引用造成的内存泄漏问题,netscape navigator 4.0 开始采用标记清除法
到了 2008 年,ie、firefox、opera、chrome 和 safari 都在自己的 javascript 实现中采用标记清理(或 其变体),只是在运行垃圾回收的频率上有所差异。
思路
在变量进入执行上下文时打上“进入”标记同时在变量离开执行上下文时也打上“离开”标记从此以后,无法访问这个变量在下一次垃圾回收时进行内存的释放function example(n){ const a = 1, b = 2, c = 3; return n * a * b * c;}// 标记example进入执行上下文const n = 1; // 标记n进入执行上下文example(n); // 标记a,b,c进入执行上下文console.log(n); // 标记a, b, c离开执行上下文,等待垃圾回收
const和let声明提升性能
const和let不仅有助于改善代码风格,同时有利于垃圾回收性能的提升const和let使js有了块级作用域,当块级作用域比函数作用域更早结束时,垃圾回收程序更早介入尽早回收该回收的内存,提升了垃圾回收的性能v8引擎的垃圾回收
v8引擎的垃圾回收采用标记清除法与分代回收法
分为新生代和老生代
新生代
新生代垃圾回收采用scavenge 算法
分配给常用内存和新分配的小量内存
内存大小
32位系统16m内存64位系统32m内存分区
新生代内存分为以下两区,内存各占一半from spaceto space运行
实际运行的只有from spaceto space处于空闲状态scavenge算法
当from space内存使用将要达到上限时开始垃圾回收,将from space中的不可达对象都打上标记将from space的未标记对象复制到to space。解决了内存散落分块的问题(不连续的内存空间)相当于用空间换时间。然后清空from space、将其闲置,也就是转变为to space,俗称反转。新生代 -> 老生代
新生代存放的是新分配的小量内存,如果达到以下条件中的一个,将被分配至老生代内存大小达到from space的25%经历了from space <-> to space的一个轮回
老生代
老生代采用mark-sweep标记清除和mark-compact标记整理
通常存放较大的内存块和从新生代分配过来的内存块
内存大小32位系统700m左右64位系统1.4g左右分区old object space字面的老生代,存放的是新生代分配过来的内存。large object space存放其他区域放不下的较大的内存,基本都超过1mmap space存放存储对象的映射关系code space存储编译后的代码回收流程标记分类(三色标记)未被扫描,可回收,下面简称1类扫描中,不可回收,下面简称2类扫描完成,不可回收,下面简称3类遍历采用深度优先遍历,遍历每个对象。首先将非根部对象全部标记为1类,然后进行深度优先遍历。遍历过程中将对象压入栈,这个过程中对象被标记为2类。遍历完成对象出栈,这个对象被标记为3类。整个过程直至栈空mark-sweep标记完成之后,将标记为1类的对象进行内存释放
mark-compact
垃圾回收完成之后,内存空间是不连续的。
这样容易造成无法分配较大的内存空间的问题,从而触发垃圾回收。
所以,会有mark-compact步骤将未被回收的内存块整理为连续地内存空间。
频繁触发垃圾回收会影响引擎的性能,内存空间不足时也会优先触发mark-compact
垃圾回收优化
增量标记如果用集中的一段时间进行垃圾回收,新生代倒还好,老生代如果遍历较大的对象,可能会造成卡顿。增量标记:使垃圾回收程序和应用逻辑程序交替运行,思想类似time slicing并行回收在垃圾回收的过程中,开启若干辅助线程,提高垃圾回收效率。并发回收在逻辑程序执行的过程中,开启若干辅助线程进行垃圾回收,清理和主线程没有任何逻辑关系的内存。内存泄露场景全局变量
// exm1function example(){ exm = 'lebron' }// exm2function example(){ this.exm = 'lebron'}example()
未清除的定时器
const timer = setinterval(() => { //...}, 1000)// clearinterval(timer)
闭包
function debounce(fn, time) { let timeout = null; return function () { if (timeout) { cleartimeout(timeout); } timeout = settimeout(() => { fn.apply(this, arguments); }, time); };}const fn = debounce(handler, 1000); // fn引用了timeout
未清除的dom元素引用
const element = { // 此处引用了dom元素 button:document.getelementbyid('lebron'), select:document.getelementbyid('select')}document.body.removechild(document.getelementbyid('lebron'))
如何检测内存泄漏这个其实不难,浏览器原带的开发者工具performance就可以
步骤f12打开开发者工具选择performance工具栏勾选屏幕截图和memory点击开始录制一段时间之后结束录制结果堆内存会周期性地分配和释放如果堆内存的min值在逐渐上升则存在内存泄漏
优化内存使用1、尽量不在for循环中定义函数
// exmconst fn = (idx) => { return idx * 2;}function example(){ for(let i=0;i<1000;i++){ //const fn = (idx) => { // return idx * 2; // } const res = fn(i); }}
2、尽量不在for循环中定义对象
function example() { const obj = {}; let res = ""; for (let i = 0; i < 1000; i++) { // const obj = { // a: i, // b: i * 2, // c: i * 3, // }; obj.a = i; obj.b = i * 2; obj.c = i * 3; res += json.stringify(obj); } return res}
3、清空数组
arr = [0, 1, 2]arr.length = 0; // 清空了数组,数组类型不变// arr = [] // 重新申请了一块空数组对象内存
【推荐学习:javascript高级教程】
以上就是javascript有gc吗的详细内容。
