面试问题整理
# 内存管理
# 什么是缓冲区溢出?有什么危害?其原因是什么?
缓冲区溢出是指当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。
危害有以下两点:
- 程序崩溃,导致拒绝额服务
- 跳转并且执行一段恶意代码
造成缓冲区溢出的主要原因是程序中没有仔细检查用户输入。
# 分页和分段有什么区别?
段式存储管理是一种符合用户视角的内存分配管理方案。在段式存储管理中,将程序的地址空间划分为若干段(segment),如代码段,数据段,堆栈段;这样每个进程有一个二维地址空间,相互独立,互不干扰。段式管理的优点是:没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)
页式存储管理方案是一种用户视角内存与物理内存相分离的内存分配管理方案。在页式存储管理中,将程序的逻辑地址划分为固定大小的页(page),而物理内存划分为同样大小的帧,程序加载时,可以将任意一页放入内存中任意一个帧,这些帧不必连续,从而实现了离散分离。页式存储管理的优点是:没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满)。
两者的不同点:
- 目的不同:分页是由于系统管理的需要而不是用户的需要,它是信息的物理单位;分段的目的是为了能更好地满足用户的需要,它是信息的逻辑单位,它含有一组其意义相对完整的信息;
- 大小不同:页的大小固定且由系统决定,而段的长度却不固定,由其所完成的功能决定;
- 地址空间不同: 段向用户提供二维地址空间;页向用户提供的是一维地址空间;
- 信息共享:段是信息的逻辑单位,便于存储保护和信息的共享,页的保护和共享受到限制;
- 内存碎片:页式存储管理的优点是没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满);而段式管理的优点是没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)。
# 物理地址、逻辑地址、线性地址
- 物理地址 它是地址转换的最终地址,是内存单元真正的地址。如果采用了分页机制,那么线性地址会通过页目录和页表的方式转换为物理地址。如果没有启用则线性地址即为物理地址
- 逻辑地址 在编写c语言的时候,通过&操作符可以读取指针变量本身的值,这个值就是逻辑地址。实际上是当前进程的数据段的地址,和真实的物理地址没有关系。只有当在Intel实模式下,逻辑地址==物理地址。我们平时的应用程序都是通过和逻辑地址打交道,至于分页,分段机制对他们而言是透明的。逻辑地址也称作虚拟地址
- 线性地址 线性地址是逻辑地址到物理地址的中间层。我们编写的代码会存在一个逻辑地址或者是段中的偏移地址,通过相应的计算(加上基地址)生成线性地址。此时如果采用了分页机制,那么吸纳行地址再经过变换即产生物理地址。在Intelk 80386中地址空间容量为4G,各个进程地址空间隔离,意味着每个进程独享4G线性空间。多个进程难免出现进程之间的切换,线性空间随之切换。基于分页机制,对于4GB的线性地址一部分会被映射到物理内存,一部分映射到磁盘作为交换文件,一部分没有映射,通过下面加深一下印象
# 虚拟内存的应用与优点
虚拟内存很适合在多道程序设计系统中使用,许多程序的片段同时保存在内存中。当一个程序等待它的一部分读入内存时,可以把CPU交给另一个进程使用。虚拟内存的使用可以带来以下好处:
- 在内存中可以保留多个进程,系统并发度提高
- 解除了用户与内存之间的紧密约束,进程可以比内存的全部空间还大
# 颠簸
颠簸本质上是指频繁的页调度行为,具体来讲,进程发生缺页中断,这时,必须置换某一页。然而,其他所有的页都在使用,它置换一个页,但又立刻再次需要这个页。因此,会不断产生缺页中断,导致整个系统的效率急剧下降,这种现象称为颠簸(抖动)。
内存颠簸的解决策略包括:
- 如果是因为页面替换策略失误,可以修改替换算法来解决这个问题;
- 如果是因为运行的程序太多,造成程序无法同时将所有频繁访问的页面调入内存,则要降低多道程序的数量;
- 否则,还剩下两个办法:终止该进程或增加物理内存容量。
# mmap是啥
mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。如下图所示:
参考:
认真分析mmap:是什么 为什么 怎么用 - 胡潇 - 博客园 (cnblogs.com) (opens new window)
# VIRT(虚拟内存)RES(常驻内存)和SHR(共享内存)
虚拟内存
虚拟内存别称虚拟存储器 (opens new window)(Virtual Memory)。电脑 (opens new window)中所运行的程序均需经由内存 (opens new window)执行,若执行的程序占用内存很大或很多,则会导致内存消耗殆尽。为解决该问题,Windows (opens new window)中运用了虚拟内存 (opens new window)技术,即匀出一部分硬盘空间来充当内存使用。
常驻内存
常驻内存,这个术语来自MSDOS的时代。MSDOS是单任务的运行环境,系统一般不允许两个以上程序同时运行。也就是说,如果你正在运行一个任务,而又想运行另外一个任务,你必须退出当前的任务。有一种辅助工具程序,能假装退出,而仍驻留于内存当中,让你运行其它的应用。而当你需要的时候,可以用热键随时把该驻留程序 (opens new window)激活。这样就看起来像多任务,并用这种方式为用户提供方便。一般这样的程序都是很小的应用程序。占用内存极少。或者占用高端内存。在现代的多任务操作系统 (opens new window)中,常驻内存程序,只不过是个名词而已,其内涵早就失去了实际意义。这不是说没有可以常驻内存的程序,而是把程序区分为常驻内存和非常驻内存,无论从技术或者使用的角度来说,都毫无意义。
共享内存
这个是进程之间的通信方式,进程之间可以通过共享内存来进行通信
# 地址空间是啥
下图是一个程序的进程空间分布图
虚拟内存基本思想:每个进程有用独立的逻辑地址空间,内存被分为大小相等的多个块,称为页(Page).每个页都是一段连续的地址。对于进程来看,逻辑上貌似有很多内存空间,其中一部分对应物理内存上的一块(称为页框,通常页和页框大小相等),还有一些没加载在内存中的对应在硬盘上
# 进程相关
# 说一说进程同步有哪几种机制
原子操作、信号量机制、自旋锁管程、会合、分布式系统
# 说一下你对并发和并行的理解
- 并发 一个处理器同时处理多个任务
- 并行 多个处理器或者是多核的处理器同时处理多个不同的任务
# 同步、异步、阻塞、非阻塞的概念
同步和异步是操作系统的层面,然后阻塞和非阻塞内核层面的操作
同步 当一个同步调用发出后,调用者要一直等待返回结果。通知后,才能进行后续的执行。
异步 当一个异步过程调用发出后,调用者不能立刻得到返回结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。
阻塞 是指调用结果返回前,当前线程会被挂起,即阻塞。
非阻塞 是指即使调用结果没返回,也不会阻塞当前线程。
# fork时发生了什么
在linux调用fork函数的时候,会创建一个子进程,fork()函数其实是调用发起_fork()系统调用,控制权由用户态转为内核态
内核会分配新的内存块和内核数据结构给子进程(也就是PCB task_struct结构体),
然后内核会将父进程的部分数据内容以二进制形式拷贝到子进程,
下来再将所谓的子进程PCB加入到管理链表中(操作系统管理进程就是将程序用PCB描述,用链式结构进行管理),
然后从内核态返回用户态(父进程fork返回进程pid,子进程返回0),
后开始调度器调度。
但是我们要注意一点,fork之前父进程独立执行,fork之后父子进程分别执行自己的执行流,但是谁先执行由调度器调度。
这里还有一点需要注意,当子进程刚被创建出来,父子进程不再写入的时候,父子进程是数据共享一份,代码独有,但是当有任意一方试图写入数据的时候,便已写时拷贝的方式各自拥有一份数据
这就是所谓的写时拷贝。
参考: