2.7 操作系统 内存

一、malloc 默认大约能申请 3 个多 G 的虚拟堆内存。

二、内存管理方式

1、块式管理

把主存分为一块一块的,即使程序片段只有几个字节,也只能将这一块分配给它,会造成很大的内存碎片。

2、页式管理

页的大小固定,由系统决定,系统将逻辑地址划分为页号和页内地址两部分。可以离散分配,减少内存碎片,但仍然容易产生内部碎片。但页长与程序的逻辑大小没关系。

3、段式管理

段是按照程序的自然分界划分的并且长度可以动态改变的区域。段与段在内存中可以不相邻,实现了离散分配。

4、段页式管理

1)用分段方法来分配和管理虚拟存储器。程序的地址空间按逻辑单位分成基本独立的段,而每一段有自己的段名,再把每段分成固定大小的若干页。

2)用分页方法来分配和管理内存,即把整个主存分成与上述页大小相等的存储块,可装入作业的任何一页。程序对内存的调入或调出是按页进行的,但它又可按段实现共享和保护。

三、虚拟内存与物理内存

定义:虚拟内存是一种抽象的内存管理技术,为每个进程提供一个独立的虚拟地址空间,操作系统通过内存管理单元(MMU)将虚拟地址映射到物理地址。

虚拟内存的好处:扩展内存容量、内存隔离、内存连续,简化程序设计、提高系统整体性能(只将最常用的数据放到物理内存中)。

虚拟内存工作原理:

1、分页机制:虚拟内存+通过分页将内存划分为固定大小的页面(通常是 4KB),并将物理内存也划分为同样大小的页面框。当进程需要访问某个虚拟内存页时,操作系统会将其映射到物理内存中的页面框。如果该页面当前不在物理内存中(即页面缺失),会抛出异常,操作系统会从硬盘中加载该页面。

2、页面交换:当物理内存不足时,操作系统会将一些页面从内存交换到磁盘,释放内存空间供其他进程使用。这个过程称为页面交换,通常会影响系统的性能,因为磁盘访问速度比内存慢得多。

3、内存管理单元(MMU):内存管理单元(MMU)是硬件组件,负责将虚拟地址转换为物理地址。

四、解释下内存碎片:内碎片,外碎片

内碎片是在已分配的内存块内部产生的(包括间隙和页剩余部分,这些间隙无法重新再分配),而外碎片是在未分配的空闲内存区域中形成的(连续的虚拟内存区域太小,不能满足进程的内存分配请求,也就导致这些虚拟内存对应物理内存无法进行分配)。

五、页表

定义:页表是操作系统中用于管理虚拟内存与物理内存之间映射关系的数据结构。它将虚拟内存中的虚拟地址映射到物理内存中的物理地址。操作系统通过页表来记录每个虚拟页面(虚拟地址空间中的一个固定大小的块)和物理页面框(物理内存中的一块对应大小的区域)之间的对应关系。页表的存在使得操作系统能够实现虚拟内存的管理和隔离

作用:1、实现虚拟内存和物理内存的映射;2、帮助系统进行内存管理;3、记录了访问权限信息,能够进行内存保护;4、通过虚拟化技术让每个虚拟机有独立的虚拟地址空间。

为什么需要页表?

1、提供虚拟内存支持。

2、提高物理内存利用率:系统只会将实际需要的页面加载到物理内存中,而不是将整个进程的内存加载到物理内存。

3、内存的保护和隔离:页表提供内存保护机制。

4、简化程序设计。

5、支持多线程、多进程:确保进程间的隔离,每个进程有独立的页表。

六、虚拟地址到物理地址的映射

虚拟地址结构划分:页表索引(高20位)+页内偏移量(低12位)。

查询页表:通过页表索引找到页表项(里面存放了对应的物理页面框地址)

系统将虚拟页的高位替换为物理页的高位。

将物理地址高位与虚拟地址低位组合,得到最终物理地址。

线性地址 = 页目录索引 + 页表索引 + 页内偏移。

页目录地址+页目录索引,找到页表地址。

页表地址+页表索引,找到页表项,进而找到物理页地址。

物理页地址+页内偏移,找到最终的物理地址。

七、逻辑地址、线性地址、物理地址

逻辑地址是程序产生的段内偏移地址;虚拟地址是段选择符+段内偏移地址;线性地址是虚拟到物理转换的中间层(段基址+段内偏移地址)

八、OS 中的缺页中断是什么意思?

malloc 在分配内存时,只是在虚拟地址中分配,并没有在对应的物理内存中进行分配。当进程访问虚拟地址对应的是外存地址,就会触发缺页中断。这些页只在外存中,操作系统在缺页中断时,会从外存中找到对应的外存页,将其调入物理内存中。

缺页中断处理过程:

1、中断响应:CPU 检测到缺页中断后,会暂停当前进程的执行,保存当前进程的上下文信息,如程序计数器、寄存器等,以便后续恢复进程执行。

2、查找页面:操作系统的内存管理模块会根据缺页地址,在进程的页表中查找对应的页面信息,确定该页面在磁盘中的位置。

3、页面置换(若需要):如果此时物理内存已满,没有足够的空闲空间来加载所需页面,操作系统就需要选择一个物理页面进行置换。选择置换页面的算法有多种,如先进先出(FIFO)算法、最近最少使用(LRU)算法等。

4、加载页面:将所需页面从磁盘读入到物理内存中分配的空闲页面位置,并更新页表,将该页面的状态标记为 “在内存中”。

5、恢复进程:将之前保存的进程上下文信息恢复,让 CPU 继续执行引发缺页中断的指令,此时该指令就能访问到所需的页面。

九、OS 缺页置换算法如何实现

当访问一个不在物理内存中的页,且物理内存已满,就需要从物理内存中调出一个页,与要访问的页进行置换。

先进先出(FIFO)算法:按照进入内存中的顺序将物理内存页排成队列,将最先进入队列的页调出,将要访问的页插入队尾。

最近最少使用(LRU)算法:置换最近一段时间以来最长时间未访问过的页面。

十、系统调用是什么?与库函数的区别?

系统调用是 OS 提供给用户空间使用内核服务的程序接口,是属于系统的一部分;库函数不依赖平台,是面向应用开发的函数方法,是为了让人们编程方便。

十一、为什么要有 page cache,操作系统怎么设计的 page cache ?

原因:因为磁盘访问速度远低于内存,为减少磁盘 I/O 操作,将 Page Cache 作为磁盘在内存中的缓存。在读取数据时,可以从 Page Cache 中进行读取;在写入数据时,可以先将数据写入 Page Cache 中,由操作系统在适当时机将数据写入磁盘。

设计:通常采用双向链表来组织 Page Cache 中的页面。包括空闲链表,用于管理内存中的空闲页面;活跃链表,用于存储正在被访问或近期被访问过的页面。这样的链表结构便于快速查找、插入和删除页面。

十二、给你一个类,里面有static,virtual之类的,来说一说这个类的内存分布?

1、static 修饰符

1)修饰成员变量

静态数据成员分配在全局数据区,属于类所有,不属于某一具体对象,在没实例化之前就可以使用。初始化需要在对应 cpp 里,否则会造成重复定义问题。

2)修饰成员函数

静态成员函数不具有 this 指针,只能访问静态数据成员变量和静态成员函数,无法访问非静态的成员函数和变量。

2、实现动态多态的两个条件

1)虚函数;2)一个基类指针或引用指向派生类对象。

3、virtual 修饰符

1)包含虚函数的类

当类包含虚函数时,编译器会为该类创建一个虚函数表(VTable),同时在类的实例里安插一个虚函数表指针(VPTR),指向这个虚函数表。虚函数表存有该类所有虚函数的地址。

2)包含虚基类的类

当类使用虚继承时,编译器会为每个使用虚继承的类创建一个虚基类表(VBTable),并且在派生类的实例中插入一个虚基类表指针(VBPtr),指向这个虚基类表。虚基类表存储着该类到虚基类的偏移量。

C++/嵌入式开发 秋招面经 文章被收录于专栏

一名985硕,在25年秋招中斩获多个C++/嵌入式开发Offer。本专栏将分享我的面经,涵盖C/C++、操作系统、计算机网络、ARM体系与架构、Linux应用/驱动开发、Qt、通信协议及开发工具链等核心内容。

全部评论

相关推荐

评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务