阻塞 和 挂起
阻塞是进程的一种状态,而挂起是行为。
线程的五个状态:新建状态、就绪状态、运行状态、阻塞状态及死亡状态。
阻塞
进程的阻塞是指使一个进程让出处理器,去等待一个事件,如等待资源、等待I/O完成、等待一个事件发等,通常进程自己调用阻塞原语阻塞自己,所以,是进程自主行为,是一个同步事件。当一个等待事件结束会产生一个中断,从而,激活操作系统,在系统的控制之下将被阻塞的进程唤醒,如I/O操作结束、某个资源可用或期待事件出现。进程的阻塞和唤醒显然是由进程切换来完成。
挂起
当出现了引起挂起的事件时系统或进程利用挂起原语把指定进程或处于阻塞状态的进程挂起。被挂起进程会被暂时调离出内存,通常在资源紧张时挂起阻塞进程。其执行过程大致如下:检查要被挂起进程的状态,若处于活动就绪态就修改为挂起就绪,若处于阻塞态,则修改为挂起阻塞。
当系统资源尤其是内存资源充裕或进程请求激活指定进程时,系统或有关进程会调用激活原语把指定进程激活。
内核态
内核态(特权模式)和用户态(用户模式/应用程序态)是CPU的两种状态。
CPU只有在内核态才可以访问硬件、控制内存……
当一个进程在执行用户自己的代码时处于用户态,权限较低,可以防止应用程序进行越权的操作。
用户态可以通过调用系统调用切换为内核态,来使用操作系统的功能。
CPU在触发中断时也会陷入内核态,进行多任务切换。
计算机启动过程:
1、计算机通电后加载BIOS;
> BIOS是一组固化到计算机内主板上一个ROM芯片上的程序,它保存着计算机最重要的基本输入输出的程序、开机后自检程序和系统自启动程序。
2、BIOS启动如下功能:
- 进行计算机自检,尝试识别可引导设备(光盘、硬盘、U盘、网络等);
- 自举装载:在自检成功后将磁盘(或者其他设备上)上起始位置的 主引导记录(512B)加载到指定内存处,并从此处开始执行;
- 主引导记录运行事先安装的bootloader(引导加载程序);
- bootloader加载操作系统(不同操作系统bootloader不同,比如Linux可能是grub),转交控制权;
- 载入内核,启动初始进程。
以Linux系统为例,先载入/boot目录下面的kernel。内核加载成功后,第一个运行的程序是/sbin/init。它根据配置文件(Debian系统是/etc/initab)产生init进程。这是Linux启动后的第一个进程,pid进程编号为1,其他进程都是它的后代。
然后,init线程加载系统的各个模块,比如窗口程序和网络程序,直至执行/bin/login程序,跳出登录界面,等待用户输入用户名和密码。
至此,全部启动过程完成。
内存对齐
如果一个变量的内存地址正好是它长度(字节为单位)的整数倍,它就称作是自然对齐的。
作用:
CPU读取内存粒度一般是其字长(4或8字节),当CPU读取非对齐内存时,有可能需要两次访问,而对齐内存只需要一次。
对齐规则:
对于标准数据类型来说,它的地址只要是其长度的整数倍就对齐了。而复合的数据类型按照下列原则对齐:
-
对于数组, 其元素按照基本数据类型进行对齐就行。(数组元素的存放在内存中是连续的, 第一个对齐了, 后面的都自动对齐了)
-
对于联合体, 其长度最大的数据类型对齐就可以了。
-
对于结构体, 保证结构体中每个元素能够正确对齐即可。
为了保证结构体每一个成员都能对齐,需要引入填补机制。规则如下:
- 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;
- 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。
栈和堆分配内存哪个更快?
栈更快。
栈:
由编译器自动分配和释放,在函数执行时,函数内部的局部变量都可以在栈上创建(使用PUSH 指令),函数执行结束时,这些存储单元将则被自动释放。
需要注意的是,栈内存分配运算内置于处理器的指令集中,它的运行效率一般很高,但是分配的内存容量有限。
堆:
也称为动态内存分配,由程序员手动完成申请和释放。程序在运行的时,由程序员使用内存分配函数(如 malloc 函数)来申请内存,使用完之后再由程序员自己负责使用内存释放函数(如 free 函数)来释放内存。
malloc会调用系统调用函数sbrk()、mmap()。
函数调用压栈过程:
https://www.cnblogs.com/roy-blog/p/6367093.html
进程5种状态
新建态:进程刚被创建,未提交执行;
就绪态:进程具备运行条件,等待系统分配处理器以便运行。
运行态:进程占有处理器正在运行。
等待(wait)态:又称为阻塞(blocked)态或睡眠(sleep)态,指进程不具备运行条件,正在等待某个事件的完成。
终止态:进程自然结束或被终止,不再执行,但依然保留在操作系统中等待善后。