内存管理GC
代码。
async函数时Generator函数的语法糖,async函数的返回值是promise对象,generator函数的返回值是 iterator对象方便多了,同时,还可以使用 await 代替then 方法指定下一步操作。
function f() {
return Promise.resolve('TEST');
}
// asyncF is equivalent to f!
async function asyncF() {
return 'TEST';
}
await 会阻塞下面的代码(即加入微任务队列),先执行 async外面的同步代码,同步代码执行完,再回到 async 函数中,再执行之前阻塞的代码
定时器原理
var id=setTimeout(fn,delay); 初始化一个只执行一次的定时器,这个定时器会在指定的时间延迟 delay 之后调用函数 fn ,该 setTimeout 函数返回定时器的唯一 id,我们可以通过这个 id 来取消定时器的执行。
var id=setInvertal(fn,delay); 与 setTimeout 类似,只是它会以 delay 为周期,反复调用函数 fn,直到我们通过id取消该定时器。
clearInterval(id),clearTimeout(id); 这两个函数接受定时器的 id,并停止对定时器中指定函数的调用。
定时器指定的延迟时间不能得到保证
在浏览器中,因为所有的JS代码都运行在单一线程中,异步事件只有在被触发时,其回调才会得到执行。
因为单线程的缘故,在同一时间只能执行一条 JavaScript 代码,每一个代码块都会阻塞其他异步事件的执行。
这就意味着,当一个异步事件发生的时候(例如鼠标点击,定时器触发,一个 XMLHttpRequest 请求完成),它进入了代码的执行队列,执行线程空闲时会依照该执行队列中顺序依次执行代码。
总结:
JavaScript 引擎是单线程的,会迫使异步事件进入执行队列,等待执行。
setTimeout 和 setInterval 在执行异步代码时从根本上是有所不同的。
如果一个定时器事件被阻塞,使得它不能立即执行,那么它会被延迟,直到下一个可能的时间点,才被执行(这可能比你指定的 delay 时间要长)
Interval 的回调有可能‘背靠背’无间隔的执行,这种情况是说 interval 的回调函数的执行时间比我们指定的 delay 时间还要长
内存管理GC
栈中JS引擎自动清除.
JS 引擎可以通过逃逸分析辨别出哪些变量需要存储在堆上,哪些需要存储在栈上。
自动垃圾回收机制:找出不使用的值,释放内存。
函数运行结束,没有闭包或引用,局部变量被标记清除
全局变量:浏览器卸载页面被清除
垃圾回收算法
不论哪个垃圾回收算法,都有一套共同的流程:
- 标记内存空间中的活动对象(在使用中的对象)和非活动对象(可以回收的对象)。
- 删除非活动对象,释放内存空间。
- 整理内存空间,避免频繁回收后产生的大量内存碎片(不连续内存空间)。
引用计数
一个对象是否有被引用(循环引用导致内存泄露)
策略:跟踪每个变量被使用的次数
- 当声明了一个变量且将一个引用类型赋值给该变量时,这个值的引用次数为1
- 若同一个值又被赋给另一个值,引用数 +1
- 如果该变量的值被其他的值覆盖了,则引用次数减 1
- 当这个值的引用次数变为 0 的时候,说明没有变量在使用,这个值没法被访问了,回收空间,垃圾回收器会
在运行的时候清理掉引用次数为 0 的值占用的内存
缺点:
需要一个计数器,所占内存空间大,因为我们也不知道被引用数量的上限。
解决不了循环引用导致的无法回收问题。
标记清除
将“不再使用的对象”定义为“无法到达的对象”
工作流程:
- 垃圾收集器在运行时给内存变量加上标记,假设内存汇总所有对象都是垃圾,全标记为0
- 从根部出发,寻找可到达的变量,并将其标记清除,改为1
- 留有标记的变量就是待删除的,即标记为0,销毁并回收它们占用的内存
- 把所有内存中对象标记修改为0,等待下一轮垃圾回收
优点:实现简单,一位二进制位就可以为其标记
缺点:
内存碎片化,空闲内存块不连续分配速度慢,因为即使使用first-fit策略,其操作仍是一个O(n)的操作,最坏情况是每次都要遍历到最后,因为碎片
化,大对象的分配速率会更慢
- 先在 from 空间进行内存分配,当空间被占满时,标记活动对象,并将其复制到 to 空间。
- 复制完成后,将 from 和 to 空间互换。
由于直接将活动对象复制到另一半空间,没有了清除阶段的开销,所以能在较短时间内完成回收操作,并且每次复制的时候,对象都会集中到一起,相当于同时做了整理操作,避免了内存碎片的产生。
优点:吞吐量高、没有碎片
缺点:首先,复制操作需要时间成本的,若堆空间很大且活动对象很多,则每次清理时间会很久;其次,将空间二等分的操作,让可用的内存空间直接减少了一半。
标记整理
也叫做标记-压缩算法。结合了标记-清除和复制算法的优点。
- 从一个 GC root 集合出发,标记所有活动对象。
- 将所有活动对象移到内存的一端,集中到一起。
- 直接清理掉边界以外的内存,释放连续空间。
该算法既避免了标记-清除法产生内存碎片的问题,又避免了复制算法导致可用内存空间减少的问题。当然,该算法也不是没有缺点的,由于其清除和整理的操作很麻烦,甚至需要对整个堆做多次搜索,故而堆越大,耗时越多。
识别内存泄露
经验法则是,如果连续五次垃圾回收之后,内存占用一次比一次大,就有内存泄漏。
这就要求实时查看内存的占用情况。
在 Chrome 浏览器中,我们可以这样查看内存占用情况
1.打开开发者工具,选择 Performance 面板
2.在顶部勾选 Memory
3.点击左上角的 record 按钮
4.在页面上进行各种操作,模拟用户的使用情况
5.一段时间后,点击对话框的 stop 按钮,面板上就会显示这段时间的内存占用情况
造成内存泄露
- 意外的全局变量
- 被遗忘的定时器和回调函数
- 事件监听没有移除
- 没有清理的DOM 引用
- 子元素存在的内存泄漏
- 闭包
V8对GC优化
栈中数据回收:执行状态指针 ESP 在执行栈中移动,移过某执行上下文,就会被销毁;
对象复制排列到空闲区域,没有内存碎片,完成后,清理对象区域,角色反转;
新生代区域两次垃圾回收还存活的对象晋升至老生代区域;
主垃圾回收器负责老生区垃圾回收,大对象,存活时间长;
新生代区域采用标记-清除算法回收垃圾:从根元素开始,递归,可到达的元素活动元素,否则是垃圾数据;
为了不造成卡顿,标记过程被切分为一个个子标记,交替进行。
分代式垃圾回收
以上所说的垃圾清理算法每次垃圾回收时都要检查内存中所有的对象,酱紫对一些大,老,存活时间长的对象来说,同新,小,存活时间短的对象一个频率的检查很不好,因为前者需要时间长且不需要频繁进行清理,后者恰恰相反,如何
优化?
分代式
分代式机制把一些新、小、存活时间短的对象作为新生代,采用一小块内存频率较高的快速清理,而一些大、老、存活时间长的对象作为老生代,使其很少接受检查,新老生代的回收机制及频率是不同的,可以说此机制的出现很
大程度提高了垃圾回收机制的效率
新老生代
V8的GC策略基于分代式垃圾回收机制,将堆内存分为新生代和老生代两区域,采用不同的垃圾回收策略进行垃圾回收.
新生代的对象是存活时间较短的对象,简单来说就是新产生的对象,通常只支持1-8M的容量,而老生代的对象为存活时间较长或常驻内存的对象.
新生代垃圾回收
新生代中对象一般存活时间较短,采用 scavenge 算法处理,在Scavenge算法具体实现中,主要采用一种复制式的方法及Cheney算法:
其将新生代空间对半分为 from-space 和 to-space 两个区域。新创建的对象都被存放到 from-space,当空间快被写满时触发垃圾回收。先对 from-space 中的对象进行标记,完成后将标记对象复制到 to-space 的一端,然后将两
个区域角色反转,就完成了回收操作。
由于每次执行清理操作都需要复制对象,而复制对象需要时间成本,所以新生代空间会设置得比较小(1~8M)。
当一个对象经过多次复制后依然存活,它将会被认为是生命周期较长的对象,随后会被移动到老生代中,采用老生代的垃圾回收策略进行管理
另外还有一种情况,如果复制一个对象到空闲区时,空闲区空间占用超过了 25%,那么这个对象会被直接晋升到老生代空间中,设置为 25% 的比例的原因是,当完成 Scavenge 回收后,空闲区将翻转成使用区,继续进行对象内
存的分配,若占比过大,将会影响后续内存分配
老生代垃圾回收
老生代中的对象一般存活时间较长且数量也多,使用了两个算法,分别是标记清除算法和标记压缩算法。
什么情况下对象会出现在老生代空间中:
新生代中的对象是否已经经历过一次 Scavenge 算法,如果经历过的话,会将对象从新生代空间移到老生代空间中。
To 空间的对象占比大小超过 25 %。在这种情况下,为了不影响到内存分配,会将对象从新生代空间移到老生
全站分卷索引 · 154 卷
- 1代码随想录知识星球精华(最强八股文)第五版(前端篇))
- 2html语义化
- 3src 和 href 的区别
- 4link 与 @import 的区别
- 5iframe
- 6CSS
- 7伪元素和伪类
- 8block,inline,inline-block
- 9重排、重绘和合成
- 10盒子模型
- 11margin 合并
- 12margin和padding 的值为百分比时
- 13浮动
- 14定位
- 15CSS选择器
- 16CSS选择器优先级
- 17选择器权重Specificity
- 18CSS属性继承
- 19不可/可继承属性
- 20display: none与 visibility: hidden的区别
- 21background-size
- 22client、offset&scroll
- 23CSS3新特性
- 24flex布局
- 25常见布局
- 26三栏布局
- 27垂直居中
- 28水平垂直居中
- 29CSS画三角形
- 30使chrome支持12px以下文字
- 31响应式布局
- 32媒体查询
- 33过渡与动画
- 34JavaScript 动画 和 CSS动画
- 35SCSS
- 36CSS性能优化
- 37有哪些数据类型
- 38判断数据类型
- 39类型转换
- 40parseInt&parseFloat
- 41浮点数求和步骤
- 42十进制小数转二进制
- 430.1+0.2 为什么不等于 0.3
- 44undefined 和 undeclared 的区别
- 45JavaScript NaN 属性
- 46isFinite()&isNaN()
- 47数组
- 48对原数组有影响
- 49对原数组无影响
- 50数组去重
- 51数组拍平
- 52ES6新增的数组方法
- 53判断是否存在某个值
- 54arguments为啥不是数组
- 55对象
- 56遍历对象的方法
- 57判断对象是否具有属性
- 58for in 和 for of 的区别
- 59继承方式
- 60instanceof
- 61深浅拷贝
- 62freeze属性
- 63函数
- 64函数柯里化
- 65函数的 length
- 66箭头函数和普通函数区别
- 67构造函数
- 68执行上下文
- 69作用域
- 70作用域和作用域链
- 71闭包和内存泄漏
- 72this
- 73关于 this 的指向问题
- 74改变this指向的方法(bind / call / apply)
- 75字符串
- 76DOM和事件
- 77哪些事件支持冒泡
- 78阻止冒泡
- 79HTMLCollection、NodeList
- 80dom.onclick 和 dom.addEventListener的区别
- 81e.target和e.currentTarget
- 82页面生命周期
- 83异步
- 84内存管理GC
- 85其它
- 86JavaScript 中日期时间格式转换
- 87input和object实现双向绑定
- 88JSON.stringify()
- 89escape、encodeURI&encodeURIComponent
- 90移动端滚动穿透和溢出
- 91ES6
- 92Map字典
- 93... 与rest
- 94proxy
- 95模块化
- 96Ajax、Fetch和Axios
- 97Webpack
- 98浏览器:事件循环
- 99浏览器内核
- 100浏览器同源策略
- 101输入URL回车后发生了什么
- 102HTTP
- 103HTTP 2.0
- 104浏览器存储
- 105鉴权
- 106Webstorage
- 107浏览器执行机制
- 108AST 抽象语法树
- 109性能优化
- 110CSS
- 111网络相关
- 112使用HTTP2.0
- 113图片
- 114CDN图片
- 115其他文件优化
- 116降低APP首页开屏渲染时间
- 117页面白屏
- 118HTTPS中间人攻击
- 119Web Worker
- 120Service Worker
- 121微前端
- 122Vue
- 123v-show 和 v-if 的区别
- 124双向数据绑定的原理
- 125Vue中的插槽使用
- 126Vue中的key
- 127Vue过滤器
- 128Vue中Scoped原理
- 129Vue中$nextTick的使用
- 130Vue中实现组件通信的方式
- 131Vue-router
- 132Vue路由传参
- 133前端路由
- 134Vuex
- 135虚拟DOM
- 136DIFF 算法
- 137Vue3和Vue2有哪些区别
- 138说一说你对React的理解
- 139React事件机制
- 140说一说你对react refs的理解
- 141react中key的作用
- 142组件开发
- 143有状态组件和无状态组件
- 144函数式组件和类组件的区别
- 145PureComponent&Component
- 146常见 Hooks
- 147状态管理
- 148redux toolkit
- 149React18新特性
- 150client中的createRoot取代以前的ReactDOM.render
- 151Suspense
- 152新的Hooks
- 153VDom一定更快吗
- 154Fiber