虚拟内存
操作系统将物理内存以页划分,每个页4K大小,之后再内存分配时,以页为单位进行分配,
页表中每个虚拟地址对应一个物理页,4G的内存,只需要8M的页表即可。
通过虚拟内存机制,每个进程都仿佛占用了所有内存,进程访问内存时,会查看虚拟地址,判断有无对应的物理地址,其间可能要进行中断,替换等操作,最终定位到相应的物理地址,访问数据。
其中,MMU(内存管理单元)将用于虚拟地址到物理地址的映射
为了加快速度,操作系统加入了缓存机制,基于局部性原理,可大大提高进程运行速度。
缺页中断:即进程访问的虚拟地址未分配物理地址,系统产生缺页中断,切换到内核态为进程虚拟地址分配物理空间。
为什么要设置虚拟内存:
- 内存完整性
通过虚拟内存机制,每个进程都好似分配了一块大的连续内存,故在编写程序时,不用考虑大块内存地址的分配问题,总认为系统有足够内存即可
2.安全
由于物理地址均需要通过页表来寻址,操作系统可在页表上添加访问权限标志,实现内存的权限控制。
3.方便共享数据。
各进程虚拟地址可指向同一物理进程,便于数据通信和共享。
4.SWAP机制
当物理内存不足时,将内存中部分暂时不用的数据存入SWAP分区(一般为磁盘),让优先级高得进程先占用物理内存,当需要用到这些数据时,再加载入内存。
可避免OOM-KILLEr
- TCP面向连接,UDP面向无连接(不需要三次握手)
- TCP面向字节流,UDP面向报文
- UDP对应用层的报文,不合并不拆分,**保留这些报文的边界**
- TCP是可靠的,安全的。UDP不可靠但实时性高
- TCP有确认和重传,流量控制,拥塞控制
- UDP无连接,无重传,不需要维持双方在线
- 为什么连接时3次握手,关闭时却是四次握手
因为服务器接收到客户端发来的SYN报文时,说明客户端请求连接,此时直接发送SYN+ACK报文,SYN用来同步,ACK用以应答。即服务器告诉客户端可以连接,ACK说明收到了客户端的请求连接,客户端回复ACK告知收到服务器报文,连接建立
- 为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才返回CLOSE状态
重发可能丢失的最后一个ACK;
为什么是2MSL呢,因为若服务器未收到最终的ACK,会不断重发FIN。其中2MSL就是一个发送和一个恢复的最大时间,直到2MSL时,客户端还未收到服务器的FIN,说明大概率服务器已成功接收ACK则结束TCP连接
- 为什么三次握手而不是两次握手
- 防止出现失效的连接请求被服务端接收,从而让服务端误进入ESTABLISHED
- 为什么要4次挥手
因为TCP是全双工通信!支持半关传输
- 第一次挥手:即主动发送方(FIN)告知被动方,要断开连接了,仅代表主动方不继续传送数据,但可接收数据
- 第二次挥手(ACK):即被动方发送的ACK,告知主动方我知道你想断开连接了;避免主动方再未收到ACK的情况下,不停的发FIN报文
- 第三次挥手(FIN):同上,告知主动方我也要断开连接了,我不发数据了,此时被动方进入LAST-ACK状态
- 第四次挥手(ACK):同上,此时主动方进入TIME-WAIT状态,被动方接收到LAST-ACK则释放连接。
由于有半关传输机制,故必须采用四次握手。
TCP不存在半开传输,故只需要三次握手
- 全连接与半连接
linux内核协议栈为tcp连接管理两个队列,即半链接队列(SYN-SENT,SYN-RECV),和全链接队列(established),该两队列的溢出很容易忽视,对于一些断连接应用(nginx,PHP)更容易爆发。一旦溢出,从服务端看cup、线程状态和负载正常,但压力上不去。
客户端看来,请求耗时高,同时客户端会出现请求超时,socket读写超时等现象
- 解决:
- 客户端:对于TCP连接失败,增加重试机制和超时时间;启用长连接机制
- 服务器:修改内核配置,增加半连接队列和全连接队列大小
- 保活机制
避免客户端出现故障,导致服务器白等,浪费资源;
服务器每接收到一次客户端请求后,都会重新复位这个计时器,时间通常设置为2小时,若两小时都未接收到客户端任何数据,则会发送一个探测报文,并每隔75s发送一次;若连续10个探测报文依旧没回复,则关闭连接
TCP是全双工连接,断开连接时两端都需发送FIN和ACK
- <br />
滑窗与流控;
- 滑动窗口:
- 用于流量控制
- 第一次发送数据的窗口大小【链路带宽决定】
- 后续窗口有TCP报头中的”窗口”位来协商
- 拥塞控制(cwnd ,ssthresh)
- 慢开始(以2倍增长到ssthresh)
- 拥塞避免(转为线性增加)
- 若发生超时重传,判断网络出现拥塞
- cwnd=1
- ssthresh/=2
- 快恢复(三次ACK)
- 接收到三次ACK
- cwnd=ssthresh/2=ssthresh
- 直接进入拥塞避免
- 接收到三次ACK
- 滑动窗口:
DNS过程,DNS具体细节(我没懂让我讲什么更细节的东西😮💨),如果找不到对应ip会怎样?
以www.qq.com为例子
- DNS客户机
- 先检查操作系统或者浏览器缓存是否有网址映射
- 客户机到服务器查询
- 查询本地DNS服务器是否有网址映射
- DNS服务器缓存(缓存服务器到服务器的查询)若有网址映射,则返回该IP地址
- 服务器到服务器查询
- 本地DNS将请求转发至13个根服务器,根服务器返回一个顶级域名服务器
.com
- 本地DNS将请求转发至顶级域名服务器
.com
,若.com
无法解析,则发送到下一级的DNS服务器qq.com
- 递归重复上述查询,直到找到对应ip
- 本地DNS将请求转发至13个根服务器,根服务器返回一个顶级域名服务器
- select id from xxx limit 100,100 与 select id from xxx limit 1000000,100分析一下哪条效率更高;
- volatile的作用,底层实现;
- 作用
volatile为类型修饰符,指示编译器对其修饰的对象不执行优化,在单线程中仅能起到限制优化的作用;
用volatile修饰的变量,编辑器不会将其保存于寄存器中,而是每次都访问该变量在内存中的实际位置。
故多线程共享的基本变量一定要加volatile修饰符
- 底层实现
阻止编译器优化(会优化一些无用操作,即对变量的访问操作),直接从内存地址访问变量
- 注意事项
https://www.cnblogs.com/god-of-death/p/7852394.html
C/C++ Volatile变量,与非Volatile变量之间的操作,是可能被编译器交换顺序的。
- 什么是死锁、死锁原因、死锁必要条件
死锁:多个进程在运行过程中因争夺资源而造成的一种僵局,若无外力作用,它们将无法继续运行
原因:
- 竞争不可剥夺资源
- 可剥夺资源:CPU,主存,不会产生死锁
- 不可剥夺资源:当该类资源分配给进程时,不能强制收回,必须等进程释放
- 进程间推进顺序非法
必要条件:
- 互斥:排他性,一段时间某资源仅为以进程占有
- 请求和保持:当进程请求资源阻塞时,对其所获得的资源不释放
- 不剥夺:进程已获得资源未使用完之前,不可剥夺,仅可自己释放
- 循环等待:发生死锁时,必然存在一个进程资源的环形链
预防死锁:
- 资源一次性分配
- 只要有一个资源未分配,不分配其余资源
- 若进程仅分配了部分资源,而得不到剩下的资源,释放所有已分配资源
- 资源有序分配法
避免死锁:
避免死锁策略中,允许进程动态的申请资源,故在申请资源前,可计算资源分配的安全行
银行家算法
- 线程间通信、进程间通信
进程间通信:
- 管道
- 命名管道
- 共享内存
- socket通信
- 信号(SIGPIPE): 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
- 信号量(计数锁):信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
- 消息队列
线程间通信:
- volatile关键字
- 条件变量condition_variable
- pthread_cond_wait等等
- pthread_cond_notify
- 互斥锁
- mutex
- lock_guard
- unique_guard
- atomic基本类型原子操作
- 信号量
- 读写锁
- 协程的优点:
- 没有线程切换的开销,执行销量高;
- 只有一个线程,共享资源不加锁。
- 还有一些忘记了,主要的部分就是 计网和操作系统;