《码农翻身》笔记
本文最后更新于:2022年6月13日 中午
通过拟人化的方式讲解了计算机中的很多较难理解的知识,内容覆盖面较广,且未太深入,读起来易理解
线程的切换
线程池等待cpu
进行调度,每个线程只会被运行一段时间,然后切换到其它线程
死锁,两个线程相互等对方释放,出现死锁
按照资源的“大小”顺序来申请锁
tcp/ip
三次握手,分组交换,失败重传
缓存
缓存比内存和硬盘快
程序的局部性原理
时间局部性
当程序的某条指令被执行后,不久后可能再次被执行;如果某些数据被访问后,则可能会被再次访问
空间局部性
当访问一个内存单元后,过不久其附近的内存单元也可能被访问
通过这个原理可以将程序分块进行装载到内存中,不用一次性全部加载
将这一小块称为页框page frame
,每页4kb
大小
流水线
提前准备好其它事情类似于多辆车要洗车,打蜡
进程控制块
MMU 内存管理单元
地址的动态重定位
例如两个程序都操作了500的位置,第二个程序的起始地址就不是0,cpu
操作时会先加上基址寄存器的指再去操作
分时系统
每个程序只会运行一段时间
虚拟内存:分页
给程序分配一块很大的虚拟内存,然后映射真实物理地址,操作系统维护一个页表来管理
如果访问到没有被映射到物理内存的页面,就会产生页中断,触发缺页处理程序,操作系统会再去硬盘中调取,把内容读取到内存,然后重新修改页表
分段
将程序进行分段
代码段
数据段
堆栈段
当程序访问非法内存的时候,操作系统会重新获得控制权,从而kill掉进程
程序在不断的运行中会分块加载到内存中,专业术语叫做分页
文件的存放
采用索引式存放,专门找一个磁盘块来记录文件的磁盘号,这样无论是顺序访问,还是随机访问就都很快了,缺点是这个索引块也要占空间
后面出现了inode
的结构,里面不仅仅保存了磁盘块编号,还保存了权限,所有者,修改日期等,如果磁盘块的编号过多,可以使用间接块,指向另一个磁盘块,有一次间接块,二次间接块和三次间接块
为了防止在对文件的操作的同时出现了系统崩溃,在操作前操作系统都会先记录操作日志,重启时检查日志项,以查看哪一项未做,然后重新做一遍
操作日志(
Journal
) 文件系统
管理空闲块
链式法
位图法,给每个磁盘块通过0
和1
来标记是否被使用,这种方式简洁高效,节省空间
文件系统
有很多种类,如NTFS
,FAT
,Ext2
,Ext3
等
例如 LInux Ext2
为例,文件系统在这个硬盘上的布局是有MBR(Master Boot Record)
和多个磁盘分区组成的, MBR
中会记录引导代码和磁盘分区表,磁盘分区表会记录磁盘的起始位置,是否位活动分区,如果是互动分区,操作系统会找到它,然后进行载入
中断式I/O
例如在读取文件的过程中,cpu
可以去执行其它进程,等文件读取完成,会发出一个中断信号,cpu
会执行中断程序,然后来读取拿到的文件
在处理中断的过程中,有一个中断控制器,它会负责调度中断的优先级,然后分配给cpu处理
这是一种异步的,事件驱动的处理思想,在node
和ajax
中应用广泛
转换代码
词法分析 生成
tokens
语法分析 生成
ast
语法数语义分析 检查代码是否编写正确,标识符类型,作用域是否正确,运算是否合法
中间代码生成
代码优化
代码生成
线程锁
自旋锁,多个线程操作同一个共享变量的时候,操作系统会给他分配一个锁,只有获得这个锁,才可以对这个变量进行操作,与此同时,其它线程会不断的轮训来抢这把锁,除非它的时间片到了,必须让出cpu的执行时间。
问题:
如果函数出现递归,那么就会出现死锁,
函数第一次运行的时候申请到了锁🔐,然后递归再次运行自己,这时候锁已经被申请过了,所以第二次只能等待,轮训的去申请,这时候就出现了死锁
改进:
解决重入问题,每次申请的锁的时候记录一下是谁申请的,再用一个计数器来记录重入的次数,当这个持有锁的函数再次进入的时候把计数器+1,释放锁的时候也是一样的,把计数器-1,直到减为0
解决****占用问题:当其它线程尝试申请锁的时候,会把它放到队列中,不会再轮训的去申请锁了,等到锁被释放了,再通知这个线程去抢锁
信号量
再生产者,消费者模型中,可能会出现相互等待的问题,如消费者消费过快,需要等待生成者的数据,或者生成者过快,需要等待消费者消费完。
此时操作系统通过信号量来解决该问题
尾递归
当递归调用师函数体中最后执行的语句,并且它的返回值不属于表达式的任何一部分时,这个递归就是尾递归,有些语言的现代编译器会对这种代码进行优化,递归的时候不会生成新的堆栈帧,会复用堆栈。
js的Safari已经对尾递归进行了优化,但是其它浏览器都没有对其进行实现
事务
要么全部完成,要不一个不做
原子性 Atomicity
一致性 Consistency
隔离性 Isolation
持久性 Durability
简称ACID
幂等性
多次执行,不会有变化
锁
互斥锁
同一时间只有获得锁的线程可以去操作共享的资源,其它线程会被阻塞,放在锁池(Lock Pool
)中
采用不加锁的方式
线程读取值,如
A
值做完一系列操作
准备重新写入
A
,这时候会拿A
和内存中的值进行比较,如果一致则写入,不一致则再次循环
  这一步是原子性操作,不会存在数据不一致的问题 compareAndSwap,简称CAS
java
提供了一系列Atomic
类,,针对对象的比较是比较引用,同时增加版本号,以解决删除后再次添加的问题
web
网络
非对称加密
我给A发消息的时候,用A的公钥进行加密,A收到后会用自己的私钥进行解密
A的公钥是公开的,地球人都知道
但是这种RSA的加密,解密速度太慢了
改进
先用加密的方式发送一个对称加密的私钥,后续的加密解密都采用这个对称加密的私钥,这个速度比之前快了百倍
redis
缓存一致性hash
算法
余数算法
先对key
进行hash
,然后用这个结果对服务器的个数取余,这个弊端是,出现新增和删除集群的时候,缓存会出现问题
就近缓存
redis
集群的服务器分布在类似时钟的环形上,当新增和删除服务器的时候只会影响一定区间的数据
hash槽
每台服务器管理固定区间的缓存,如果有新增服务器,则其他服务器可以将一部分数据交给它管理
故障转移
hash
槽分组后,每组都有多台服务器(node
),其中会有一台master
,其它被称为salve
,master
和slave
的数据是一样的,只是做了备份,如果master
挂了slave
会替换掉master
,这里会用某种算法选出一个slave
作为新的master
redis
集群(cluster)
会管理客户端发过来的请求,控制具体在哪个服务器获取数据
nginx高可用性
需要多台nginx
服务器
通过keepalived
形成master-slave
的结构,当一台挂了,其它的会顶上, 对外暴露的是统一ip
地址
mysql高可用性
也采用master-slave
的架构
master
主写,slave
主读,实现读写分离,在这之上加一层中间层,来分发读写的操作,发到不同的数据库中
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议,转载请注明出处。