面试题10

103 阅读9分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1. 简述操作系统是如何申请、管理内存的

(1) 如何申请内存:

从操作系统的角度来看,进程分配内存有两种方式,分别由两个系统调用完成:*brk和mmap

(2)如何管理内存:

1.物理内存:物理内存有四个层次,分别是寄存器、高速缓存、主存和磁盘。

寄存器:速度最快、量少、价格贵。

高速缓存:次之。

主存:再次之。

磁盘:速度最慢、量多、价格便宜 在这里插入图片描述 操作系统会对物理内存进行管理,有一个部分被称为内存管理器,它的主要工作是有效的管理内存,记录哪些内存是正在使用的,在进程中需要时分配以及在进程完成时回收内存。

2.虚拟内存:操作系统为每一个进程分配一个独立的地址空间,但是虚拟内存与物理内存存在映射关系,通过页表寻址完成虚拟地址和物理地址的转换。

2. 简述Linux系统态和用户态,什么时候会进入系统态?

(1)系统态与用户态:

系统态(内核态)与用户态是操作系统的两种运行级别。内核态拥有最高权限,可以访问所有系统指令;用户态只能访问一部分指令。

(2)什么时候进入系统态:

一共有三种方式:a、系统调用;b、异常;c、设备中断。其中系统调用是主动的,另外两种是被动的。

(3)为什么区分系统态和用户态:

在CPU的所有指令中,有些指令是非常危险的,如果错用,将导致整个系统崩溃。比如:清理内存、设置时钟等。所以区分内核态与用户态主要是出于安全的考虑

3. 简述LRU算法以及实现方式

LRU算法用于缓存淘汰。思路是将缓存中最近最少使用的对象删除掉。

实现方式:利用双向链表和哈希表

当需要插入新的数据项的时候,如果新数据项在链表中存在(一般称为命中),则把该节点移到链表的头部,如果不存在,则新建一个节点,放到链表的头部,若缓存满了,则把链表的最后一个节点删除即可。

在访问数据的时候,如果数据项在链表中存在,则把该节点移到链表的头部,否则返回-1。这样一来在链表尾部的节点就是最近最久未访问的数据项。

LRU缓存C++的实现:给出一个链接吧,大家可以自己写,反正我是写出来的146.LRU缓存

4. 一个线程占多大内存?

Linux的栈是通过缺页来分配内存的,不是所有栈地址空间都分配了内存。因此8M是最大消耗,实际的内存消耗指挥略大于实际需要的内存(内部损耗,每个在4k以内)。

5. 什么是页表,为什么要有?

页表是虚拟内存的概念。操作系统虚拟内存到物理内存的映射表,就被称为页表。

原因:如果将每一个虚拟内存的 Byte 都对应到物理内存的地址,每个条目最少需要 8字节(32位虚拟地址->32位物理地址),在 4G 内存的情况下,就需要 32GB 的空间来存放对照表,那么这张表就大得真正的物理地址也放不下了,于是操作系统引入了页(Page)的概念。

在系统启动时,操作系统将整个物理内存以 4K 为单位,划分为各个页。之后进行内存分配时,都以页为单位,那么虚拟内存页对应物理内存页的映射表就大大减小了,4G 内存,只需要 8M 的映射表即可,一些进程没有使用到的虚拟内存,也并不需要保存映射关系,而且Linux 还为大内存设计了多级页表,可以进一页来减少内存消耗。

6. 简述操作系统中的缺页中断

(1)缺页异常:

malloc和mmap函数在分配内存时只是建立了进程虚拟地址空间,并没有分配虚拟内存对应的物理内存。当进程访问这些没有建立映射关系的虚拟内存时,处理器自动触发一个缺页异常,引发缺页中断。

(2)缺页中断:

缺页异常后将产生一个缺页中断,此时操作系统会根据页表中的外存地址在外村中找到所缺的一页,将其调入内存。

缺页中断与一般中断一样,需要经历四个步骤:保护CPU现场、分析中断原因、转入缺页中断处理程序、恢复CPU现场,继续执行。

缺页中断与一般中断的区别: (1)在指令执行期间产生和处理缺页中断信号 (2)一条指令在执行期间,可能产生多次缺页中断 (3)缺页中断返回的是执行产生中断的一条指令,而一般中断返回的是执行下一条指令

7. 说说虚拟内存分布,什么时候会由用户态陷入内核态?

(1)虚拟内存分布:

在这里插入图片描述

(2)用户空间:

1.代码段.text:存放程序执行代码的一块内存区域。只读,代码的头部还会包含一些只读的常量变量。

2.数据段.data:存放程序中已初始化的全局变量和静态变量的一块内存区域。

3.BSS段.bss:存放程序中未初始化的全局变量和静态变量的一块内存区域。

4.可执行程序在运行时又会多出来两个区域:堆区和栈区

堆区:动态申请内存用,堆地址从低地址向高地址增长。

栈区:存储局部变量、函数参数值。栈从高地址向低地址增长。是一块连续的空间。

5.最后还有一个共享区,位于堆和栈之间。

内核空间:DMA区、常规区、高位区。

(3)什么时候进入内核态:

共有三种方式:a.系统调用;b.异常;c.设备中断。其中系统调用是主动的,另外两种是被动的。

8. 简述一下虚拟内存和物理内存,为什么要用虚拟内存,好处是什么?

(1)物理内存:

物理内存有四个层次,分别是寄存器、高速缓存、主存、磁盘。

寄存器:速度最快、量少、价格贵。

高速缓存:次之。

主存:再次之。

磁盘:速度最慢、量多、价格便宜。

操作系统会对物理内存进行管理,有一个部分称为内存管理器(memory manager),它的主要工作是有效的管理内存,记录哪些内存是正在使用的,在进程需要时分配内存以及在进程完成时回收内存。

(2)虚拟内存:

操作系统为每一个进程分配一个独立的地址空间,但是虚拟内存。虚拟内存与物理内存存在映射关系,通过页表寻址完成虚拟地址和物理地址的转换。

(3)为什么要用虚拟内存:

因为早期的内存分配方法存在以下问题: (1)进程地址空间不隔离。会导致数据被随意修改

(2)内存使用效率低

(3)程序运行的地址不确定。操作系统随机分配为进程分配内存空间,所以程序运行的地址是不确定的。

(4)使用虚拟内存的好处:

1.扩大地址空间。每个进程独占一格4G空间,虽然真实物理内存没那么多;

2.内存保护:防止不同进程对物理内存的争夺和践踏,可以对特定内存地址提供写保护,防止恶意篡改。

3.可以实现内存共享,方便进程通信。

4.可以避免内存碎片,虽然物理内存可能不连续,但映射到虚拟内存上可以连续。

(5)使用虚拟内存的缺点:

1.虚拟内存需要额外构建数据结构,占用空间。

2.虚拟地址到物理地址的转换,增加了执行时间

3.页面换入换出耗时

4.一页如果只有一部分数据,浪费内存。

9. 虚拟地址到物理地址怎么映射的?

操作系统为每一个进程维护了一个从虚拟地址到物理地址的映射关系的数据结构,叫页表。页表中的每一项都记录了这个页的基地址。

三级页表转换方法:(两步)

1.逻辑地址转线性地址:段起始地址 + 段内偏移地址 = 线性地址

2.线性地址转物理地址:

(1)每一个32位的线性地址被划分为三部分:页目录索引(DIRECTORY,10位)、页表索引(TABLE,10位)、页内偏移(OFFSET,12位)

(2)从cr3中取出进程的页目录地址(操作系统调用进程时,这个地址被装入寄存器中),页目录地址 + 页目录索引 = 页表地址;页表地址 + 页表索引 = 页地址;页地址+ 页内偏移 = 物理地址 在这里插入图片描述 按照上面的两步法,就完成了一个三级页表从虚拟地址到物理地址的转换。

10. 说说堆栈溢出是什么,会怎么样?

堆栈溢出就是不顾栈中分配的局部数据块大小,向该数据块写入了过多的数据,导致数据越界。常指调用堆栈溢出,本质上是一种数据结构的满溢情况。堆栈溢出可以理解为两个方面:堆溢出和栈溢出。

1.堆溢出:比如不断地new一个对象,一直创建新的对象,而不进行释放,最终导致内存不足。将会报错:OutOfMemory Error。

2.栈溢出:一次函数调用中,栈中将被依次压入:参数、返回地址等,而方法如果递归比较深或者进去死循环,就会导致栈溢出。将会报错:StackOverflow Error。