浏览器V8是怎么进行垃圾回收的

news2024/12/24 1:45:37

面试相关问题解答

1、浏览器V8是怎么进行垃圾回收的

浏览器的内存占用是有限制的:

64位系统:
	物理内存 > 16G =>  最大堆内存限制为4G
	物理内存 < 16G =>  最大堆内存限制为2G
32位系统:
	最大堆内存限制为1G

为什么浏览器要对占用内存做限制呢?

在程序运行的过程中,我们要将不用的内存释放出来,否则复杂的程序会占用很大的内存,导致程序运行缓慢或者卡顿。JavaScript的运行时单线程的,在执行垃圾回收时会阻塞JavaScript应用执行,直到垃圾回收结束才继续执行JavaScript应用逻辑,这种阻塞被称为“全停顿”(stop-the-world)

若V8的内存为1.5G,执行一次小的垃圾回收在50ms以上,做一次非增量级的垃圾回收要1s以上,这样浏览器将在这1s内失去对用户的响应,造成假死想象。如果有动画的话,动画也会收到印象,这样会造成严重的影响。

chrome是很占内存的

chrome很占内存是因为浏览器使用了多进程机制,浏览器的每一个标签页以及扩展都独立占一个进程。访问一个网站,至少要占4个进程:1个浏览器进程,一个GPU进程,一个渲染进程和一个网络进程,除此之外,可能还有多个插件组成的进程架构。而最新的Chrome浏览器运行一个网站包括:1个浏览器进程,一个GPU进程,一个网络进程,多个渲染进程和多个插件进程。【多进程架构优点是更稳定、流畅、安全】【缺点是架构复杂(各模块耦合性高、扩展性差)、占用资源高】

我们的javascript是运行在渲染进程中的。

内存空间

在javascript执行过程中,有三种类型的空间:代码空间、栈空间、堆空间

  • 代码空间:存储可执行代码
  • 栈空间:调用栈,用来存储可执行上下文,原始类型的数据值和引用类型的地址都是直接存在栈空间
  • 堆空间:存储引用类型的值
引用类型为什么一定要存在堆空间中,直接存在堆空间中行不行?

答案是不可以,javascript引擎用栈来维护程序执行期间上下文状态,如果栈空间过大,所有的数据都存在栈空间中,会影响到上下文切换的效率,进而影响到整个程序的执行效率

调用栈切换执行上下文状态

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

栈内存回收

调用一个函数时,V8引擎会创建一个函数的活动对象【执行上下文】并推入调用栈的栈顶。

活动对象包含这个函数的参数、局部变量、返回值

调用完成后,活动对象从栈中弹出,释放内存。继续执行当前执行环境下剩余的代码

当分配的调用栈空间被占满时,会引发“堆栈溢出”问题

一开始调用栈为空,直到函数被调用,便自动的加入调用栈,执行完成,调用栈自动弹出这个函数。依此类推

综上所述,栈内存是随着函数执行完成调用栈弹出活动对象时自动释放的。函数执行完毕,立即释放,节省内存空间。

堆内存回收

堆内存主要用来存放对象和动态数据的地方。是程序对于内存空间最大的一个地方。同时我们常说的垃圾回收就是指堆内存的垃圾回收。

V8使用垃圾回收机制来管理我们的堆内存。简单来说就是释放孤立(非活跃)对象使用的内存。

如何判断非活跃对象
1、引用计数

每当有引用的地方,就加一,去掉引用就减一,这种方式无法解决循环引用的问题,引用计数都无法为0,导致无法GC,所以V8没有使用这种方法

2、可访问性分析法

V8采用了这种方法。

将一个成为GCRoots的对象(在浏览器环境中,GC Roots可以包括:全局的window对象,所有原生dom节点集合等等)做为所有初始存活的对象集合,从这个对象出发,进行遍历,遍历到就认为是可访问的,标记为活动对象,需要保留,如果没有访问到,就是非活动对象,可能会被垃圾回收

在浏览器环境中,GCRoots有很多,通常包含一下几种(实际更多):

  • 全局的window对象
  • 文档DOM树。由可以通过遍历文档到达的所有原生 DOM 节点组成。
  • 存放栈上变量

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代际假说

代际假说是垃圾回收的一个关键术语,它有两个特点:

  1. 大部分变量对象的生命周期很短,比如函数内部的变量,块级作用域中的变量。这些代码在函数执行完成就可以清除。
  2. 少量的对象会存活很久,比如全局的window、Dom、全局api等对象

我们将生命周期短的对象叫新生代,生命周期长的称为老生代

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对于这两种不同的活动对象,V8分别采用不同的垃圾回收机制,达到高效垃圾回收的目的

副垃圾回收器:主要负责新生代的垃圾回收

主垃圾回收器:主要负责老生代的垃圾回收

新生代 - Scavenger算法

新生代分为两个区域,From区-To区,或者称为激活区(new space)-未激活区**(inactive new space)**,这两块区域大小相同,称为Semispace

这是一个牺牲空间换取时间的算法

1、新的对象存放在from-space

2、垃圾回收时,将还活跃的对象复制到to-space

3、清空from-space

4、将from-space和to-space互换,依此类推

scavenger算法需要在每次执行时将存活的对象复制到空闲区域,但是复制需要时间成本,如果新生区空间太大了,复制时间会比较久,所以为了执行效率,新生区空间一般都比较小。

晋升机制
  • 【第一次回收->nursery子代】 =》【第二次回收 ->intermediate子代】 =》【第三次回收->晋升到老生代】
  • to空间超过25%
老生代

主要使用【标记-清除】和【标记-整理】两个算法

Mark-Sweep【标记清除】

也就是上面提到的可访问性分析

遍历堆中的所有对象,递归调用这组跟元素,标记存活和未存活的对象,标记完成后,将未存活对象进行清除。因为这里都是生命周期长的对象,未存活对象比较少,所以效率比较高。

Mark-Compact【标记整理】

标记清除后,导致不连续的存储空间比较多,产生大量不连续的内存碎片,碎片过多无法分配大对象。

标记整理是将所有存活对象向一端移动,然后直接释放掉端边界以外的内存。从而让活动对象占连续的内存。

垃圾回收引起的性能问题

JavaScript是运行在主线程上的,为了避免JavaScript应用逻辑与垃圾回收产生不一致的冲突,垃圾回收执行时,就会占用JavaScript引擎,正在执行的JavaScript脚本会被暂停。

在V8的分代式垃圾回收中,新生代内存比较小,对应的活动对象也比较少,所以执行速度快,全停顿影响也不大。老生代内存比较大,且活动对象比较多,全堆的活动对象标记、清除、整理耗费的时间就比较长,造成的停顿会比较严重。

如何避免内存泄漏

  • 少创建全局变量

    • 全局变量会在页面关闭时才回收,所以避免创建全局变量,和没有声明的变量(变量提升,变成全局变量)
  • 手动清除定时器

    var someResource = getData();
    setInterval(function() {
        var node = document.getElementById('Node');
        if(node) {
            node.innerHTML = JSON.stringify(someResource));
        }
    }, 1000);
    someResource = null; // 定时器依然在引用变量无法回收 
    
  • 少用闭包

    var leaks = (function(){
        var leak = 'xxxxxx';// 闭包中引用,不会被回收
        return function(){
            console.log(leak);
        }
    })()
    
  • 清除DOM引用

    var element = {
      image: document.getElementById('image'),
      button: document.getElementById('button')
    };
    document.body.removeChild(document.getElementById('image'));
    // 如果element没有被回收,这里移除了 image 节点也是没用的,image 节点依然留存在内存中. 
    

    绑定事件回收

    let oDiv = document.querySelector('div');
    oDiv.onclick = function(){
                alert(111111111)
            }
    document.body.removeChild(oDiv);
    oDiv.onclick = null; // 解除事件绑定,触发垃圾回收 
    
  • 弱引用(WeakMap和WeakSet)

    • 特点:key必须是一个对象,不能是原始值
    • 优点:可以快速被垃圾回收
    • 缺点:不支持迭代以及keys(), values(),和entries()方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1419129.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云表企业级无代码案例-10天做出《运输车辆管理系统》

物流运输行业像物流公司、运输车队、出租客运公司等企业在车辆管理方面&#xff0c;因其行业特点而面临很多管理上难题&#xff1a; 一、管理的对象多&#xff1a;车辆多&#xff0c;如果有三方车辆挂靠&#xff0c;还要涉及到车主管理&#xff0c;关系错综复杂。 二、管理的信…

2024-01-24-redis4

秒杀活动 需求&#xff1a;库存中有10件商品 商品的信息自定义 同时有100个人去抢购&#xff08;这里100个人的抢购由jmeter来模拟&#xff09; jmeter的使用 在idea中将后台代码实现 package org.aaa.controller;import org.apache.commons.lang3.StringUtils; import org.sp…

LabVIEW机械臂轨迹跟踪控制

介绍了一个使用LabVIEW开发的机械臂轨迹跟踪控制系统。该系统的主要目标是实现对机械臂运动轨迹的精确控制&#xff0c;使其能够按照预定路径进行精确移动。此系统特别适用于需要高精度位置控制的场合&#xff0c;如自动化装配、精密操作等。 为了实现LabVIEW环境下的机械臂轨迹…

SpringSecurity(13)——OAuth2授权码模式

工作流程 基本使用 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId><version>2.3.12.RELEASE</version> </dependency> <dependency><groupId>…

架构篇26:高可用存储架构-集群和分区

文章目录 数据集群数据分区小结上一篇我们讨论了高可用存储架构中常见的双机架构,分别为主备复制、主从复制、双机切换和主主复制,并分析了每类架构的优缺点以及适应场景。 今天我们一起来看看另外两种常见的高可用存储架构:数据集群和数据分区。 数据集群 主备、主从、主…

macOS与Linux相互投屏的方法

很多人面对跨系统投屏都望而却步。其实只要找对方法&#xff0c;两台不同系统的电脑也可以相互投屏。 今天就来看看Linux系统和macOS系统如何相互投屏&#xff01; 第一步&#xff0c;将Linux系统电脑和macOS系统电脑连接同一网络。假设是macOS系统投屏到Linux系统&#xff0c;…

第五季特别篇:一夜杯、游戏之宴 2017.04.26

第五季特别篇&#xff1a;一夜杯、游戏之宴 2017.04.26 OVA 第1话&#xff1a;一夜酒杯 / 一夜杯OVA 第2话&#xff1a;游戏之宴 / 遊戯の宴 OVA 第1话&#xff1a;一夜酒杯 / 一夜杯 遭到独角妖袭击的妖怪夫妇日土和初菜被夏目所救&#xff0c;这对妖怪夫妇制作的酒杯&#xf…

1_Matlab基本操作

文章目录 工作环境操作界面运行命令窗口使用历史窗口当前目录浏览器工作空间浏览器帮助系统 工作环境 操作界面 命令窗口&#xff1a;用户进行操作的主要窗口。可以输入各种MATLAB的命令。函数和表达式。同时操作的运算结构也会在该窗口出现。历史命令窗口&#xff1a;记录用户…

猫宁愿饿着也不吃猫粮?公认适口性排名前十的生骨肉冻干推荐

猫宁愿饿着也不吃猫粮&#xff1f;主人需要细心观察并分析情况。如果猫咪出现呕吐、腹泻、体温异常等其他异常症状&#xff0c;可能是生病了&#xff0c;应及时就医。如果排除疾病原因&#xff0c;可能是猫粮的口感已经让猫咪感到腻味&#xff0c;不愿意再吃。此时&#xff0c;…

ArcGIS Pro如何新建字段

无论是地图制作还是数据分析&#xff0c;字段的操作是必不可少的&#xff0c;在某些时候现有的字段不能满足需求还需要新建字段&#xff0c;这里为大家讲解一下在ArcGIS Pro中怎么新建字段&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的水…

优维全面可观测产品能力分解②:变更可观测

上周&#xff0c;我们推出了优维全面可观测能力介绍的系列性文章的第一篇&#xff1a;架构可观测。优维架构可观测是从系统架构的视角来呈现链路与服务的状态数据&#xff0c;点击可回看&#xff1a;架构可观测文章。本周&#xff0c;我们将推出本系列性文章的第二篇&#xff1…

基于springboot网上书城交易平台源码和论文

在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括网上书城管理系统的网络应用&#xff0c;在国外网上书城管理系统已经是很普遍的方式&#xff0c;不过国内的书城管理系统可能还处于起步阶段。网上书城管理系统具有网上书城信…

巴厘行记(五)——情人崖

欢迎览阅《巴厘行记》系列文章 巴厘行记巴厘行记&#xff08;一&#xff09;——海神庙 巴厘行记&#xff08;二&#xff09;——乌布之夜 巴厘行记&#xff08;三&#xff09;——Auntie和Mudi 巴厘行记&#xff08;四&#xff09;——乌布漫游 巴厘行记&#xff08;五&a…

TypeScript实战系列之合理运用类型

目录 介绍any 和 unknownerve 的用途断言type 和 interfacedeclare 关键字的作用联合类型 和 类型守卫交叉类型 介绍 这篇主要介绍下ts 常用的基本类型和一些常用的技巧性技能 any 和 unknow any 和 unknown 是两个类型关键字&#xff0c;它们用于处理类型不确定或未知的情况…

羊奶温和无副作用,对五脏六腑有益

羊奶温和无副作用&#xff0c;对五脏六腑有益 羊奶一直以来都被视为一种高营养价值的饮品。与普通的牛奶相比&#xff0c;羊奶含有更多的维生素和矿物质&#xff0c;对人体的健康有着更多的益处。羊奶不仅温和无副作用&#xff0c;而且对五脏六腑都有着独特的滋补作用。 首先&…

day30_HTML

day25后几天为答疑和测试&#xff0c;第二阶段学习第一天是day30 在今日内容 0 复习昨日 1 本周安排 2 第二阶段介绍 3 HTML 0 复习昨日 1 本周安排 前面的Java知识 类,对象,属性,方法 String,日期操作,包装类操作 集合操作 本周 HTML 1天CSS 1天JavaScript 3天 前端知识比后…

OpenGL/C++_学习笔记(四)空间概念与摄像头

汇总页 上一篇: OpenGL/C_学习笔记&#xff08;三&#xff09; 绘制第一个图形 OpenGL/C_学习笔记&#xff08;四&#xff09;空间概念与摄像头 空间概念与摄像头前置科技树: 线性代数空间概念流程简述各空间相关概念详述 空间概念与摄像头 前置科技树: 线性代数 矩阵/向量定…

Linux系统——正则表达式

有一段时间本机访问量过高&#xff0c;如何查看日志提取出访问量前十的信息 1.使用提取命令&#xff08;cut、awk、sed&#xff09;提取出ip地址的那一列 2.使用sort按数字排序&#xff0c;将相同的地址整合到一起 3.使用uniq -c统计出数量 4.使用sort 数字 数字倒序排序 5.最…

[C语言][C++][时间复杂度详解分析]二分查找——杨氏矩阵查找数字详解!!!

一&#xff0c;题目 遇到的一道算法题&#xff1a; 1&#xff0c;已知有一个数字矩阵&#xff08;row行&#xff0c;col列&#xff09;&#xff0c;矩阵的每行 从左到右 递增&#xff0c;每列 从上到下 递增。 2&#xff0c;现输入一个数字 num &#xff0c;判断数字矩阵中…

防御保护常用知识

防火墙的主要职责在于&#xff1a;控制和防护 --- 安全策略 --- 防火墙可以根据安全策略来抓取流量之 后做出对应的动作 防火墙分类主要有四类&#xff1a; 防火墙吞吐量 --- 防火墙同一时间能处理的数据量多少 防火墙的发展主要经过以下阶段&#xff1b; 传统防火墙&#xf…