进程管理
进程 线程 纤程的区别
进程是OS分配资源的基本单位。
线程是执行调度的基本单位。是一个进程中的不同执行路径
两个最大的区别是:线程共享进程的内存空间,没有自己的独立空间。
线程(fiber):可以理解称为线程中的线程。 是内核态的线程
为什么会有纤程呢?
在java中JVM线程的实现方式是:经过一系列的系统调用,向OS申请,然后操作系统会产生对应的线程(这种线程叫做重量级线程),这个线程会在用户态和内核态不断切换。
这样子不断的切换需要大量的系统调用,或者说是中断(int),操作系统每次执行中断会大大的降低效率,所以就产生了用户态的线程,不需要在和操作系统打交道。
纤程的优势:
- 占用资源很少 fiber:4k 线程:1M
- 轻量级,切换容易
- 可以启动多个,10w+
进程:有独立的内存空间,在内核的数据结构叫做PCB(process control block ):进程描述符
进程调度
进程调度有不同的策略,主要分为:
- 完全公平策略Completely fair Scheduler:是按照优先级分配时间片的比例,记录每个进程的执行时间,如果一个进程执行时间不到它分配的比例,则优先执行
- 默认调度策略:FIFO 、 RR
进程分为普通进程和实时进程,对于普通进程使用CFS策略,对于实时进程,RR代表同级别的,其他的使用FIFO策略
需要注意的是:只有实时进程主动 让出或者执行完毕,普通进程才有机会运行
中断
- 硬中断:硬件通知我有事的一种通信策略 例如敲打一次键盘
- 软中断: int 80中断 ,也可以叫做系统调用,每次系统调用的时候,就相当于一次软中断
重点就是:往寄存器中装系统调用号(有200多个系统调用号,代表200多个函数)
下面通过汇编语言来理解软中断
;hello.asm
;write(int fd, const void *buffer, size_t nbytes)
;fd 文件描述符 file descriptor - linux下一切皆文件
section data
msg db "Hello", 0xA
len equ $ - msg
section .text
global _start
_start:
mov edx, len
mov ecx, msg
mov ebx, 1 ;文件描述符1 std_out
mov eax, 4 ;write函数系统调用号 4
int 0x80
mov ebx, 0
mov eax, 1 ;exit函数系统调用号
int 0x80
这里的eax、bx、cx、dx代表不同的参数。
- ax :write 函数
- bx:文件描述符 代表linux输出窗口的位置
- cx:msg代表信息
- dx:代表信息的长度
在确定了参数后,发现执行了int 0x80中断
这时候OS就会执行响应的操作,输出框就会显示msg
一个程序的执行过程,要么处于用户态要么处于内核态
内存管理
在以前的DOS时代,同一时间只能有一个进程在运行
windows可以多个进程装入内存;这个时候就会存在2个问题
- 内存撑爆
- 访问到别人的空间
为了解决这2个问题,诞生了现代的内存管理系统
- 1 分页装入(解决内存撑爆)
内存中程序分为固定大小的页框,其大小是4K,把硬盘上的程序也按照逻辑分成4k大小的块,用到哪一块,cpu就加载哪一块(硬盘到内存)。如果内存不够了,就会把最不常用的一块内存页放到swap分区–也就是著名的LRU算法
LRU算法介绍
LRU(Least Recently Used 最近最少使用)算法(leetcode146题):哈希表(保证查找操作O(1)+双向(保证左边指针指向右边)链表(保证排序操作和新增操作0(1)))
class LRUCache extends LinkedHashMap<Integer, Integer>{
private int capacity;
public LRUCache(int capacity) {
super(capacity, 0.75F, true);
this.capacity = capacity;
}
public int get(int key) {
return super.getOrDefault(key, -1);
}
public void put(int key, int value) {
super.put(key, value);
}
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
return size() > capacity;
}
}
- 2 虚拟地址空间(解决相互打扰问题)
为了保证不相互影响,让进程工作在虚拟的地址空间,程序用到的空间不在是直接的物理地址而是虚拟的地址,这样A进程就永远访问不到B进程的空间
虚拟地址是很大的,64位的操作系统有2^64byte大小的寻址空间,比实际的物理空间大很多,所以站在虚拟的角度,进程是独享整个系统+cpu,虚拟空间会把程序分成一段一段的(每一段程序的权限不同),然后在段内部就是一页一页4K大小的内存页
内存的映射:
- 段的基地址,表示在哪一段的内存
- 偏移量: 表示在段的哪一个内存页
虚拟地址(线性地址)就是:段的基地址+偏移量
如何通过虚拟地址找到物理地址?
这是通过OS+MMU(内存管理单元)来映射到物理地址
内存页就可能会遇到缺页中断:需要用到的页面内存中没有(内存页还未从硬盘load到内存中),这个时候产生缺页中断,就由内核来处理并加载
cpu如何区分一个数和一条指令:
IO总线内部分为:数据、地址、控制总线 所以是指令还是数字就看从哪条线过来的