操作系统基础知识(部分面经)
库文件
静态库:在程序的链接阶段被复制到程序中
- 静态库的文件内容,通常包含一堆程序员自定的变量与函数,其内容不像动态链接库那么复杂,在编译期间由编译器与链接器将它集成至应用程序内,并制作成目标文件以及可以独立运作的可执行文件。
- 而这个可执行文件与编译可执行文件的程序,都是一种程序的静态创建(static build)。
动态库:在运行时由系统动态加载到内存中
- 动态链接可以在首次载入的时候执行(load-time linking),这是 Linux 的标准做法,会由动态链接器ld-linux.so 完成,比方标准 C 库(libc.so) 通常就是动态链接的,这样所有的程序可以共享同一个库,而不用分别进行封装。
- 动态链接也可以在程序开始执行的时候完成(run-time linking),在 Linux 中使用 dlopen() 接口来完成(会使用函数指针),通常用于分布式软件,高性能服务器上。而且共享库也可以在多个进程间共享。
- 链接使得我们可以用多个对象文件构造我们的程序。可以在程序的不同阶段进行(编译、载入、运行期间均可),理解链接可以帮助我们避免遇到奇怪的错误。
库的好处:代码保密,方便保存分发
静态库:
命名规则:
Linux:libxxx.a
lib:前缀
xxx:库名字
.a:后缀
ar工具(archive)
ar rcs linxxx.a xxx.o xxx.o
r - 文件插入备存文件
c - 建立备存文件
s - 建立索引
动态库:
命名规则
Linux:linxxx.so
制作:
gcc -c -fpic a.c b.c
gcc -shared a.o b.o -o libab.so
操作系统中的缺页中断
操作系统发生缺页中断是应为当充许远在使用malloc与mmap等内存分配的函数时,分配的时候,仅仅时建立了进程的虚拟地址空间,并没有分配虚拟内存对应的物理地址,当进程访问这些没有建立映射的虚拟地址的时候,触发器自动触发一个缺页异常(通俗点来讲,在使用内存分配函数的时候(malloc、mmap)系统最初仅仅是知道要分配参数那么大的地址,但是还没有真正的分配,也就是只有空间,但是还没有地址,因此这个时候就会产生一个缺页中断,然后通过缺页中断的机制,进行一个地址的映射,使被分配内存者拥有真正的地址);
缺页中断:在请求分页的系统中,可以通过查询页表中的状态位来确定所要访问的页面是否存在于内存中,每当所要访问的页面不在内存中的时候,会产生一次缺页中断,然后操作系统将缺少的地址找到,调入内存
缺页中断所执行的操作:
- 保护CPU现场
- 分析中断原因
- 转入缺页中断程序进行处理
- 恢复CPU现场,继续执行
进程与线程的区别
- 进程是运行时对程序的封装,进程是操作系统进行资源的调度和分配的基本单位;而线程是进程的子任务,是CPU进行调度和分配的基本单位;
- 进程实现的是操作系统的并发;线程实现的是进程内部的并发
- 进程拥有属于自己的内存资源,而同一进程的线程则共用进程的资源,包括数据段、代码段等,但是线程拥有自己的线程栈
- 进程的通信复杂,包括了系统IPC、管道、套接字等,系统IPC又包括信号量、消息队列、共享内存等通讯方式;线程的通讯方式简单,因为同属于一个进程的不同线程是公用进程的资源
- 进程的创建与销毁对于操作系统来说,开销很大,需要分配内存空间、I/O设备等,销毁的时候还需要保存进程上下文,系统状态等,开销很大;但是线程在创建的时候,只需要保存少量的寄存器数据就可以了;
- 进程之间是相互独立的,如果某个进程挂掉,不会影响其他进程;线程之间存在联系,如果一个进程的所属线程挂掉了,那么其他县城也会挂掉,最终导致进程的死亡
进程状态切换图:动态就绪、静态就绪、动态阻塞、静态阻塞
1)创建状态:进程正在被创建
2)就绪状态:进程被加入到就绪队列中等待CPU调度运行
3)执行状态:进程正在被运行
4)等待阻塞状态:进程因为某种原因,比如等待I/O,等待设备,而暂时不能运行。
5)终止状态:进程运行完毕
出现这些状态的原因:
- 内存资源比较紧张,将暂时不能/用运行的进程换出到外存,来腾出足够的内存空间。将已经具备运行条件的进程所需的数据和程序换入到内存。
交换技术
- 当多个进程竞争内存资源时,会造成内存资源紧张,并且,如果此时没有就绪进程,处理机会空闲,I/0速度比处理机速度慢得多,可能出现全部进程阻塞等待I/O。
针对以上问题,提出了两种解决方法:
- 交换技术:换出一部分进程到外存,腾出内存空间。
- 虚拟存储技术:每个进程只能装入一部分程序和数据。
在交换技术上,将内存暂时不能运行的进程,或者暂时不用的数据和程序,换出到外存,来腾出足够的内存空间,把已经具备运行条件的进程,或进程所需的数据和程序换入到内存。
从而出现了进程的挂起状态:进程被交换到外存,进程状态就成为了挂起状态。
活动阻塞,静止阻塞,活动就绪,静止就绪(动态就绪、静态就绪、动态阻塞、静态阻塞)
- 活动阻塞:进程在内存,但是由于某种原因被阻塞了。
- 静止阻塞:进程在外存,同时被某种原因阻塞了。
- 活动就绪:进程在内存,处于就绪状态,只要给CPU和调度就可以直接运行。
- 静止就绪:进程在外存,处于就绪状态,只要调度到内存,给CPU和调度就可以运行。
会出现以下状态:
- 活动就绪 —— 静止就绪 (内存不够,调到外存)
- 活动阻塞 —— 静止阻塞 (内存不够,调到外存)
- 执行 —— 静止就绪 (时间片用完)
A* a = new A; a->i = 10;在内核中的内存分配上发生了什么?
程序内存管理
一个程序本质上都是由BSS段、data段、text段三个组成的。可以看到一个可执行程序在存储(没有调入内存)时分为代码段、数据区和未初始化数据区三部分。
BSS段(未初始化数据区):通常用来存放程序中未初始化的全局变量和静态变量的一块内存区域。BSS段属于静态分配,程序结束后静态变量资源由系统自动释放。
数据段:存放程序中已初始化的全局变量的一块内存区域。数据段也属于静态内存分配
代码段:存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域属于只读。在代码段中,也有可能包含一些只读的常数变量
text段和data段在编译时已经分配了空间,而BSS段并不占用可执行文件的大小,它是由链接器来获取内存的。
bss段(未进行初始化的数据) 的内容并不存放在磁盘上的程序文件中。其原因是内核在程序开始运行前将它们设置为0。需要存放在程序文件中的只有正文段和初始化数据段。
data段(已经初始化的数据) 则为数据分配空间,数据保存到目标文件中。
数据段包含经过初始化的全局变量以及它们的值。BSS段的大小从可执行文件中得到,然后链接器得到这个大小的内存块,紧跟在数据段的后面。当这个内存进入程序的地址空间后全部清零。包含数据段和BSS段的整个区段此时通常称为数据区。
可执行程序在运行时又多出两个区域:栈区和堆区。
栈区:由编译器自动释放,存放函数的参数值、局部变量等。每当一个函数被调用时,该函数的返回类型和一些调用的信息被存放到栈中。然后这个被调用的函数再为他的自动变量和临时变量在栈上分配空间。每调用一个函数一个新的栈就会被使用。栈区是从高地址位向低地址位增长的,是一块连续的内存区域,最大容量是由系统预先定义好的,申请的栈空间超过这个界限时会提示溢出,用户能从栈中获取的空间较小。
堆区:用于动态分配内存,位于BSS和栈中间的地址区域。由程序员申请分配和释放。堆是从低地址位向高地址位增长,采用链式存储结构。频繁的 malloc/free造成内存空