操作系统
操作系统(operation system,简称OS)是管理计算机硬件与软件资源的计算机程序。操作系统需要处理如管理与配置内存、决定系统资源供需的优先次序、控制输入设备与输出设备、操作网络与管理文件系统等基本事务。操作系统也提供一个让用户与系统交互的操作界面。
内核
内核是操作系统的基础模块,用于管理系统资源。例如提供对软件层面的抽象(例如对进程、文件系统、同步、内存、网络协议等对象的操作和权限控制),和对硬件访问的抽象(例如磁盘,显示,网络接口卡(NIC));操作系统,在内核的基础上有延伸,包括了提供基础服务的系统组件。
内核就是计算机学科意义上的操作系统,直接与硬件交互,提供CPU时间片管理、中断、内存管理、IO管理等等;一般意义上的操作系统包含的东西要更多一些,至少要有用户交互的基本程序,比如一个命令行界面和基本的指令(文件遍历、进程管理等等),或者图形界面的桌面和文件浏览器。
……
常见进程调度算法
- 先来先服务调度算法
- 短作业优先调度算法
- 时间片轮转法
- 多级反馈队列调度算法
- 优先权调度算法的类型
- 高响应比优先调度算法
硬盘基本知识
- 盘片(platter)
- 磁头(head)
- 磁道(track)
- 扇区(sector)
- 柱面(cylinder)
操作系统内存管理
操作系统内存管理主要负责内存的分配与回收(malloc 函数:申请内存,free 函数:释放内存),另外地址转换也就是将逻辑地址转换成相应的物理地址等功能也是操作系统内存管理做的事情。操作系统内存管理包括物理内存管理和虚拟内存管理。
虚拟内存
内存管理机制
- 块式管理
- 页式管理
- 段式管理
- 段页式管理
用户态和内核态
为了区分不同进程的不同权限,衍生出内核态(系统态)和用户态的概念。计算机通过CPU的一个状态字来区分当前进程属于哪个状态,内核态和用户态分别对应CPU的特权态(0级)和普通态(3级)。(注:intel CPU提供Ring0-Ring3四种级别的运行模式)
内核态
CPU可以访问内存几乎所有数据, 包括外围设备, 例如硬盘, 网卡. CPU也可以将自己从一个程序切换到另一个程序。
用户态
只能受限的访问内存, 且不允许访问外围设备. 占用CPU的能力被剥夺, CPU资源可以被其他程序获取。
系统调用
所有的用户程序都运行在用户态,有时需要执行内核态才能执行的操作(如:文件操作,IO处理,设备驱动等),这时需要一种机制,让用户态进程切换到内核态,但不能控制在内核中执行的指令,这种机制称为系统调用。CPU实现称为陷阱指令。
用户态切换到内核态的3种方式
- 系统调用
- 异常
- 外围设备中断(常见:缺页中断)
用户态线程和内核态线程
用户线程
指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。不需要用户态/核心态切换,速度快,操作系统内核不知道多线程的存在,因此一个线程阻塞将使得整个进程(包括它的所有线程)阻塞。由于这里的处理器时间片分配是以进程为基本单位,所以每个线程执行的时间相对减少。
优点:
- 线程的调度不需要内核直接参与,控制简单。
- 可以在不支持线程的操作系统中实现。
- 创建和销毁线程、线程切换代价等线程管理的代价比内核线程少得多。
- 允许每个进程定制自己的调度算法,线程管理比较灵活。
- 线程能够利用的表空间和堆栈空间比内核级线程多。
- 同一进程中只能同时有一个线程在运行,如果有一个线程使用了系统调用而阻塞,那么整个进程都会被挂起。另外,页面失效也会产生同样的问题。
缺点:
资源调度按照进程进行,多个处理机下,同一个进程中的线程只能在同一个处理机下分时复用。
内核线程
由操作系统内核创建和撤销。内核维护进程及线程的上下文信息以及线程切换。当线程进行切换的时候,由用户态转化为内核态。切换完毕要从内核态返回用户态;可以很好的利用smp(对称多处理,即利用多核cpu)。windows线程就是这样的。一个内核线程由于I/O操作而阻塞,不会影响其它线程的运行。
优点:
当有多个处理机时,一个进程的多个线程可以同时执行。
缺点:
由内核进行调度。
区别
- 内核支持线程是OS内核可感知的,而用户级线程是OS内核不可感知的。
- 用户级线程的创建、撤消和调度不需要OS内核的支持,是在语言这一级处理的;而内核支持线程的创建、撤消和调度都需OS内核提供支持,而且与进程的创建、撤消和调度大体是相同的。
- 用户级线程执行系统调用指令时将导致其所属进程被中断,而内核支持线程执行系统调用指令时,只导致该线程被中断。
- 在只有用户级线程的系统内,CPU调度还是以进程为单位,处于运行状态的进程中的多个线程,由用户程序控制线程的轮换运行;在有内核支持线程的系统内,CPU调度则以线程为单位,由OS的线程调度程序负责线程的调度。
- 用户级线程的程序实体是运行在用户态下的程序,而内核支持线程的程序实体则是可以运行在任何状态下的程序。
Java线程
JVM 自己本身有一个线程模型。在 JDK 1.1 的时候,JVM 自己管理用户级线程。这样做缺点非常明显,操作系统只调度内核级线程,用户级线程相当于基于操作系统分配到进程主线程的时间片,再次拆分,因此无法利用多核特性。 为了解决这个问题,后来 Java 改用线程映射模型,因此,需要操作系统支持。在 Windows 上是 1 对 1 的模型,在 Linux 上是 n 对 m 的模型。映射关系是操作系统自动完成的,用户不需要管。
用户态线程跟内核态线程通过内核线程的高级接口(LWP)形成一对一的关系,内核线程通过(LWP)把时间片给用户线程,当发生系统调用的时候,用户态线程通过LWP完成用户态到内核态的切换。
综上,java线程是混合型的线程模型。
进程间的通讯
- 管道(匿名管道、有名管道、流管道)
- 信号量
- 消息队列
- 信号
- 共享内存
- 套接字
负载均衡
- 二层负载均衡
负载均衡服务器对外提供一个VIP(虚拟IP),集群内部各主机拥有相同的IP地址,但是拥有不同MAC地址,负载均衡服务器通过改写请求报文中的目标MAC地址实现负载均衡。
- 三层负载均衡
负载均衡服务器对外提供一个VIP,集群内各主机IP地址不同,服务器接收到请求后,根据负载均衡算法,通过IP将请求发送至不同的主机。
- 四层负载均衡
位于OSI模型的第四层——传输层。有TCP/UDP协议,这两协议都包含了源端口/目标端口,负载均衡服务器通过修改报文的地址信息{IP(网络层IP)+端口}实现负载均衡。
- 七层负载均衡
位于第七层——应用层。常用协议:HTTP、RADIUS、DNS等。七层负载可以基于这些协议,如根据UPL、浏览器类别、语言、地理位置进行负载均衡。
select、poll和epoll区别
零拷贝
零拷贝其实是根据内核状态划分的,在这里没有经过CPU的拷贝,数据在用户态的状态下,经历了零次拷贝,所以才叫做零拷贝,但不是说不拷贝。在内核中还是有数据从硬盘拷贝到read buffer缓存区,数据的位置和长度的信息的描述符被追加到了socket buffer 缓冲区中。
X86-64体系结构
X86其实是是80X86的简称(后面三个字母),包括Intel 8086、80286、80386以及80486等指令集合,因此其架构被称为x86架构。x86-64是AMD公司于1999年设计的x86架构的64位拓展,向后兼容于16位及32位的x86架构。X86-64目前正式名称为AMD64,也就是Go语言中GOARCH环境变量指定的AMD64。
X86/AMD架构图
内存布局
- text一般对应代码段,用于存储要执行指令数据,代码段一般 是只读的。
- 然后是rodata和data数据段,数据段一般用于存放全局的数据,其中rodata是只读的数据段。
- heap段用于管理动态的数据
- stack段用于管理每个函数调用时相关的数据。
寄存器
- 状态寄存器: FLAGS和指令寄存器IP寄存器
- 通用寄存器:AX、BX、CX、DX、SI、DI、BP、SP。
注:在 X86-64中又增加了八个以R8-R15方式命名的通用寄存器。因为历史的原因R0-R7并不是通用寄存器, 它们只是X87开始引入的MMX指令专有的寄存器。在通用寄存器中BP和SP是两个比较特殊的寄存器:其中BP用于记录当前函数帧的开始位置,和函数调用相关的指令会隐式地影响BP的值;SP则对应当前栈指针的位置,和栈相关的指令会隐式地影响SP的值;而某些调试工具需要BP寄存器才能正常工作。