多进程的浏览器
浏览器的主要进程:1. 主进程 2. 网络进程 3. 渲染进程 4. GPU进程
一次页面请求到渲染的具体流程:
- 处理用户输入的URL(是内容就根据默认搜索引擎拼接URL;是URL就补充完整)
- 网络进程,发起请求
- 检查缓存
- DNS解析
- 建立TCP连接
- 发送HTTP报文
- 网络进程一旦读取到响应头,就通知主进程准备渲染进程,
- 渲染进程一边读取网络进程的响应体数据一边渲染页面(IPC通信)
- 主线程:根据HTML构建DOM树 -> 根据CSS构建CSSOM树 -> 结合成Render树 -> Layout计算 -> Layer分层 -> 每个图层paint生成绘制列表
- 合成线程:把图层划分为图块 -> 优先把视口附近的图块生成位图(交给栅格化线程池处理),栅格化期间跨进程使用GPU加速,最终位图保存在GPU内存 -> 发送DrawQuad命令让浏览器进程把页面内容绘制到内存,显示到屏幕
render 树实例:
GC
栈内存回收:ESP下移
堆内存回收:
- 基于代际假说(The Generational Hypothesis):1. 大部分对象存在时间很短 2. 不死的对象会活的更久
- 分代收集:
- 新生代(副垃圾回收器处理):存放的对象很小,生存时间很短
- 老生代(主垃圾回收器处理):存放较大对象或生存时间很长
- 回收方式:
- 新生代:分为对象区和空闲区,对象区写满就把存活的对象拷贝到空闲区,然后对象区和空闲区翻转角色
- 老生代:存放的是比较大或者生存时间久的对象,标记方式是从根元素开始遍历能达到的就是活动对象,标记清除算法(直接清除掉非活动对象造成内存碎片),标记整理算法(把活动对象移到一端,清掉以外的内存)
V8的编译器和解释器
我们编写的JS代码是不能被CPU直接执行性的,所以需要JS引擎的处理。JS引擎有2个核心:编译器和解释器
编译器流程:源代码通过词法分析生成AST,在生成中间代码,生成二进制文件,最终执行
解释器流程:源代码通过词法分析生成AST,生成字节码,解释器直接执行字节码(V8编译的字节码以哈希表的形式缓存在堆内存或硬盘里)
JIT即时编译:为了节省内存空间JS引擎会先把代码加工成字节码交给解释器执行,之后把频繁执行的字节码(热点代码)编译成效率更高的机器码
浏览器安全
同源:如果两个URL的域名,协议,端口号都相同,那么他们就是同源的
同源作用体现:
- DOM操作:JS脚本不能操作非同源的的DOM
- 数据读取:非同源不能读取cookie,localStorage,IndexDB等数据
- 网络请求:非同源不能发送XHR请求(对应Ajax跨域)
XSS(Cross Site Scripting),跨站脚本攻击(恶意脚本注入HTML或DOM,本质是用户执行了恶意脚本)
- 方式:1.直接把恶意代码存到有漏洞的服务器(类似sql注入) 2.提交内容参杂恶意代码(让用户点击混入脚本的请求,服务器在把恶意脚本返回给客户)
- 防范:1.对用户输入进行转码 2.利用CSP(禁止第三方脚本,禁止提供数据给第三方)3.cookie设置HttpOnly,JS无法操作
CSRF(Cross-site request forgery),跨站请求伪造(本质是用户点开链接,不知情发送了请求)
- 方式:黑客页面有某站点的转账请求,拿到用户登录的cookie,发送那个转账请求
- 防范:1.cookie设置SameSite 禁止第三方请求带自己站点的cookie 2.服务器验证Origin和Referer(记录请求来源的地址)3. 使用CSRF Token 植入页面,该页面的请求都会带上Token,不带Token的都是第三方
安全沙箱:把渲染进程放在安全沙箱中运行,隔离渲染进程和操作系统
V8的对象存储
JS对象的属性无非2种:数字属性和非数字属性。当我们for in 遍历对象属性的时候总是先按照数字属性从小到大的顺序,然后才是非数字属性的添加顺序。
在V8内,数字属性也叫排序属性放在对象的elements属性内,非数字属性也叫常规属性,放在对象的properties属性内。如果对象的常规属性小于10个那么可以直接放在对象上,这样访问效率就会很快,所以也叫快属性
cpu执行代码流程
cpu只能执行二进制文件,所有代码要被cpu运行最终都会变成二进制文件
程序执行过程:
- 把程序载入内存(二进制代码)
- cpu从pc寄存器拿到指令内存地址,取出内存中的指令并执行(cpu时钟周期:取出指令,分析指令,执行指令)
- pc寄存器存入下一条指令的地址
- 计算时使用通用寄存器存数据或指针