常见GC算法与V8引擎

2020-10-08  本文已影响0人  洲行

内存管理

为什么要内存管理

function fn() {
    let = arrList = []
    arrList[100000] = 'js'
}
fn()
内存持续升高没有回落

内存持续升高没有回落,就代表着内存泄漏,至于如何泄漏,这里先不纠结,这里想说的是,如果不了解内存问的话,烂代码写的多了,程序总会有意想不到的bug

// 申请
let a = {};
// 使用
a.name = 'js'
// 释放
a = null

JS垃圾回收

JS引擎知道什么是垃圾了,就会定期回收,这就是垃圾回收机制,后续阅读还需以下几个概念

let obj = {name: 'xm'}; // 当前的xm对象,就是可达的,obj指向xm这个对象的内存地址
let ali = obj; // xm对象又多一了一个引用
obj = null; // 此时将obj1的引用断掉了
// 我们的xm对象是否还是可达呢,当然是的,因为ali的引用还在
function objGroup(obj1, obj2) {
    obj1.next = obj2;
    obj2.prev = obj1;
    return {
        o1: obj1,
        o2: obj2
    }
}
let obj = objGroup({name: 'obj1'}, {name: 'obj2'});
console.log(obj)
// => 输出
{ 
  o1: { name: 'obj1', next: { name: 'obj2', prev: [Circular] } },
  o2: { name: 'obj2', prev: { name: 'obj1', next: [Circular] } } 
}
// Circular代表循环的又各自指向彼此
看看目前这几个对象

看看目前这几个对象,obj,obj1,obj2,都是可以从根上查找到的,无论找起来多么麻烦


如果删掉obj的o1属性和obj2的prev属性

如果删掉obj的o1属性和obj2的prev属性,相当于红色线条断掉,那么obj1就没有引用了,它此时就会变成垃圾,JS引擎就会回收掉它。

GC算法

垃圾回收机制的简写就是GC,GC可以找到内存中的垃圾,并释放和回收空间
GC眼里的垃圾是什么?

// 程序中不再需要使用的对象
function func() {
    name = 'zh'
    return `${name} is a coder`
}
func()
// 程序中不能再访问到的对象
function func() {
    const name = 'zh' // 变量再函数作用域中
    return `${name} is a coder`
}
func() // 执行后,就再也访问不到了

常见GC算法

引用计数算法实现原理

核心思想:设置引用数,判断引用数是否为0。
引用关系改变时,引用计数器修改引用数值,引用数字为0时立即回收。

const u1 = {age : 11}
const u2 = {age : 22}
const list = [u1.age, u2.age] // ?????
function fn1() {
    n1 = 100; // 由于没有设置关键字,他现在是挂载在window下的。window.n1 =100
    n2 = 200;
}
fn1();
// 所以以上的变量的引用计数肯定都不是0, list中还保持对u1,u2的引用
function fn2() {
    const n3 = 100; // 这里的n3,n4只能在当前的函数作用域内访问得到
    const n4 = 200;
}
fn2();
// 一旦fn2()执行结束后,在外部全局的角度去出发,就不能再找到n3n4了,n3n4身上的引用计数就=0,此时GC将他们回收。

引用计数算法优缺点

优点

缺点

// 无法回收循环引用的对象
function objGroup() {
    let obj1 = {};
    let obj2= {};
    obj1.next = obj2;
    obj2.prev = obj1;
    return 'xixi'
}
objGroup()
// 虽然obj1在函数作用域中,objGroup()执行后在全局以找不到它,
// 但是obj1还被obj2引用着,所以obj1的计数不等于0,就不会被清除
// obj2同理

标记清除算法实现原理

核心原理:将垃圾回收清除阶段,分标记和清除两个阶段完成

标记清除算法优缺点

优点

缺点

标记整理算法实现原理

标记整理可以看作是标记清除的增强

优点

认识V8

V8垃圾回收策略

我们都知道在程序的使用过程中,那么我们会用到很多的数据,而这些数据呢,我们又可以分为原始的数据和对象类型的数据,那么对于这些基础的原始数据来说,它都是有程序的语言自身来进行控制的,所以在这里我所提到的回收主要还是指的是当前存活在我们堆区里的对象数据。

V8如何回收新生代对象

V8内存分配

那么如何完成回收

V8如何回收老生代对象

老生代对象存放在右侧老生代区
老生代区在64位操作系统中位1.4G
老生代对象就是指存活时间较长的对象
比如全局对象下的变量,闭包中的变量
回收过程

细节对比
新生代区域垃圾回收采用空间换时间
老生代区垃圾回收不适合复制算法

增量标记如何优化垃圾回收


image.png

当进行垃圾回收时,是阻塞当前JS的执行的,图中上半部分是js程序执行,下半部分是垃圾回收,增量标记就是指把标记清除机制,分段进行,然后让js执行和垃圾回收能交替进行,提高效率

为什么使用Performance工具

内存问题的外在表现

监控内存的几种方式

界定内存问题的标准

监控方式
浏览器任务管理器
Timeline时序图记录
堆快照查找分离DOM

TimeLine记录内存

image.png

堆快照查找分离DOM

什么是分离DOM

已经脱离了文档的DOM,在界面也没有呈现,但是代码里依然有对其的引用,就是分离DOM

<body>
 <button id = "btn">add</button>
 <script>
     let ele;
     function fn() {
         var ul = document.createElement('ul')
         for (let i = 0; i < 10; i++){
             var ul = document.createElement('li')
             ul.appendChild(li)
         }
         ele = ul
     }
     document.getElementById('btn').onclick = fn
 </script>
</body>

看以上代码,我们创建了ul但是并没有把它插进文档,但是却使它有引用,这就是分离DOM,分离DOM是内存泄漏的常见原因


快照

判断是否频繁GC

通过Time中是否频繁的上升下降判断

chrome检查内存工具
Performance 工具指北

上一篇下一篇

猜你喜欢

热点阅读