js栈内存和堆内存与垃圾回收机制

v8作为javascirpt引擎,对变量的存储主要有两种位置:栈存储和堆存储

栈内存存储基本类型的变量:如Number,String,boolen,undefined,null,以及对对象和数组变量的指针,对象是动态分配内存,数组的初始化方式分为:

动态初始化:初始化时只指定数组长度,由系统为数组分配初始值。

静态初始化:初始化时指定每个数据元素的初始值,由系统决定数组长度

我们在代码声明变量并赋值时,所使用的对象就分配在堆中,如果申请的堆内存不够分配新的对象,将继续申请内存,知道堆的大小超过v8的限制。

这里写图片描述

var obj1={zs:'bangbang',age:'22'};

var b =obj1;

b.age=18

console.log(obj.name)//18

var c= obj.age

c=22

以上看出:当我们改变b的数据的时候,我们看到了obj1.name的数据也在改变,但是我们改变c的数据的时候发现,obj1.age的值没有变化,这说明了:b和obj1变量操作的是同一个对象,c和obj1完全独立的

v8的垃圾回收机制

在栈中变量用完之后自动释放,v8堆内存分为新生代和老生代内存

1 新生代对象

在分代的基础上,新生代的对象主要通过Scavenge算法进行垃圾回收,在Scavenge算法的具体实现中,主要采用Cheney算法,它将新生代内存一分为二,一个处于使用中,另一个处于闲置中,处于闲置中为to空间,当我们分配对象时,首先在from空间进行分配,当开始垃圾回收,首先会检查from空间的存活对象,这些存活对象会被复制到to空间中,而非存活的对象占用的空间将被释放,完成复制后,from空间和to空间的角色发生对换,Scavenge的缺点时只能使用堆内存的一半,但因为新生代兑现的生命周期较短,恰恰适合这个算法。

2老生代对象

当一个对象经过多次复制依然存活,它被认为生命周期较长的对象,这种较长生命周期的对象会被移动到老生代中,对于老生代中的对象,由于存活对象占较大比重,在采用Scavenge的方式会有两个问题:一个时存活对象较多,复制存活对象的效率将会很低;另一个问题依然时浪费一半空间的问题。为此,v8在老生代中主要采用Mark-Sweep和Mark-Compact相结合的方式进行垃圾回收。

Mark-Sweep就是我们常说的标记清除,它分为标记和清除两个阶段,在标记阶段遍历堆的所有对象,在随呼的标记清除阶段中,只清除没有被标记的对象。Sweep最大的问题就是进行一次标记清除回收后,内存空间会出现不连续的状态,所以Mark-Compact被提出来,就是标记整理的意思,在对象被标记死亡后,在整理的过程中,将活着的一下对象往一断移动,移动完成后,直接清理掉边界的内存

3,如何触发垃圾回收

提到如何触发垃圾回收,第一个要介绍的是作用域,函数执行结束后,该作用域将会销毁,同时作用域中声明的局部变量分配在该作用域上,随着作用域的销毁而销毁

1.标识符查找

所谓的标识符可以理解为变量名,js在执行中会去查找该变量定义在哪里,也就是我们常说的词法分析,最先查找的是当前作用域,如果在当前作用域中无法找到该变量的声明,将会向上级的作用域查找,直到查到为止,一层一层查找就构成了作用链,

2.变量的主动释放,如果变量是全局变量,由于全局作用域需要直到退出进程才能释放,将会导致引用的对象常驻老生代内存中


 

猜你喜欢

转载自blog.csdn.net/mrfang1413/article/details/83717102
今日推荐