java八股-操作系统

操作系统详解:功能、调度与资源管理-CSDN博客

进程是分配资源的基本单位,那么这个资源指的是什么?

  1. 内存资源

    • 这是最主要的资源之一。操作系统为每个进程分配独立的虚拟地址空间,包括代码段、数据段、堆(heap)和栈(stack)。
    • 进程在运行时需要内存来存储程序代码、全局变量、动态分配的数据以及函数调用的上下文。
  2. CPU时间

    • 操作系统通过进程调度算法,将CPU的执行时间分片分配给不同的进程,使得多个进程可以"并发"执行。
    • 虽然CPU的执行(运行)是以线程为单位,但CPU时间片的分配和调度决策通常以进程为基本单位进行考量。
  3. 文件资源

    • 进程在运行时会打开文件、管道、套接字等I/O设备。操作系统为每个进程维护一个打开文件表,记录该进程打开的所有文件描述符。
    • 这些文件描述符就是进程所拥有的资源。
  4. I/O设备

    • 进程可能需要访问打印机、磁盘、网络接口等硬件设备。操作系统负责协调这些设备的访问,确保资源不被冲突使用。
  5. 系统对象和句柄

    • 包括信号量、互斥锁、消息队列、共享内存段等用于进程间通信(IPC)和同步的内核对象。
    • 进程可以创建或打开这些对象,操作系统会为进程分配相应的句柄来引用它们。
  6. 其他内核数据结构

    • 操作系统为每个进程创建和维护一个进程控制块(Process Control Block, PCB),也称为任务控制块。
    • PCB中包含了进程的标识符(PID)、状态、程序计数器、CPU寄存器、内存管理信息、打开文件列表、优先级、记账信息等。PCB本身也是操作系统分配给进程的一种关键资源。

用户态和内核态的区别?

特性 用户态 (User Mode) 内核态 (Kernel Mode)
特权级别 高(最高)
指令权限 只能执行非特权指令 可执行所有指令(包括特权指令)
内存访问 仅限本进程地址空间 可访问所有内存
硬件访问 不可直接访问 可直接访问
运行代码 应用程序 操作系统内核
切换方式 通过系统调用、中断、异常进入 服务完成后返回用户态
安全性 出错影响小,系统稳定 出错可能导致系统崩溃
  • 内核态(Kernel Mode):在内核态下,CPU可以执行所有的指令和访问所有的硬件资源。这种模式下的操作具有更高的权限,主要用于操作系统内核的运行。
  • 用户态(User Mode):在用户态下,CPU只能执行部分指令集,无法直接访问硬件资源。这种模式下的操作权限较低,主要用于运行用户程序。

分为内核态和用户态的原因

  • 安全性:通过对权限的划分,用户程序无法直接访问硬件资源,从而避免了恶意程序对系统资源的破坏。
  • 稳定性:用户态程序出现问题时,不会影响到整个系统,避免了程序故障导致系统崩溃的风险。
  • 隔离性:内核态和用户态的划分使得操作系统内核与用户程序之间有了明确的边界,有利于系统的模块化和维护。

内核态和用户态的划分有助于保证操作系统的安全性、稳定性和易维护性。

线程的定义是什么?

线程可以理解为轻量级的进程,它是基本的CPU执行单元。由线程id、程序计数器、寄存器集合、和堆栈组成。线程不独立拥有资源。

线程的两种实现方式

用户级线程中,线程的管理都在应用程序中进行,系统会提供一个多线程的函数库,系统感知不到用户定义的多线程的存在。

内核级线程:线程的管理都在操作系统中完成,用户只有一个到内核级线程的编程接口。

进程,线程,协程的区别是什么?

概念 定义
进程 操作系统进行资源分配和调度的基本单位。每个进程都有独立的内存空间、文件描述符、环境变量等资源。
线程 进程内的执行单元 ,是CPU调度的基本单位。一个进程可以包含多个线程,这些线程共享进程的资源(如内存、文件),但拥有独立的栈和寄存器。
协程 用户态的轻量级"线程",由程序自身控制调度 ,而非操作系统。协程在单线程内通过协作式方式切换,避免了上下文切换的开销。

资源占用与开销

概念 资源占用 创建/销毁开销 上下文切换开销
进程 高(独立地址空间、PCB等) 高(涉及内存映射、权限切换)
线程 中(共享进程内存,但有独立栈) 中(共享地址空间,但需切换栈和寄存器)
协程 低(仅需少量栈空间) 极低 极低(用户态跳转,无需陷入内核)

调度方式

概念 调度者 调度类型
进程 操作系统内核 抢占式调度(时间片轮转、优先级等)
线程 操作系统内核 抢占式调度
协程 程序/运行时库(如Python的asyncio、Go的goroutine) 协作式调度(主动让出控制权)

并发与并行能力

并发能力 并行能力(多核)
进程 ✅ 可跨多核并行
线程 ✅ 可跨多核并行(但受GIL等限制)
协程 极高(可创建数万个) ❌ 通常在单线程内,不直接利用多核(需配合多线程/多进程)

为什么进程崩溃不会对其他进程产生很大影响

进程隔离性:每个进程都有自己独立的内存空间,当一个进程崩溃时,其内存空间会被操作系统回收,不会影响其他进程的内存空间。这种进程间的隔离性保证了一个进程崩溃不会直接影响其他进程的执行。

进程独立性:每个进程都是独立运行的,它们之间不会共享资源,如文件、网络连接等。因此,一个进程的崩溃通常不会对其他进程的资源产生影响。

多线程是不是越多越好,太多会有什么问题?

切换开销:线程的创建和切换会消耗系统资源,包括内存和CPU。如果创建太多线程,会占用大量的系统资源,导致系统负载过高,某个线程崩溃后,可能会导致进程崩溃。

死锁的问题:过多的线程可能会导致竞争条件和死锁。竞争条件指的是多个线程同时访问和修改共享资源,如果没有合适的同步机制,可能会导致数据不一致或错误的结果。而死锁则是指多个线程相互等待对方释放资源,导致程序无法继续执行。

进程切换和线程切换的区别?

对比项 进程切换(Process Switch) 线程切换(Thread Switch)
切换单位 不同的进程 同一进程内的不同线程
资源环境 完全不同的地址空间(内存、页表) 共享同一进程的地址空间和资源
切换开销 大(需切换页表、TLB 刷新等) 小(只需切换栈和寄存器)
CPU 缓存影响 高(缓存命中率低,性能下降明显) 低(共享内存,缓存友好)
通信方式 需 IPC(管道、消息队列等) 直接读写共享变量(需同步)
隔离性 高(一个进程崩溃不影响其他) 低(一个线程崩溃可能导致整个进程崩溃)
调度单位 是(传统) 是(现代 OS 的基本调度单位)
进程切换(Process Switch)
  • 操作系统保存当前进程的 CPU 状态(寄存器、程序计数器等)。
  • 切换页表(Page Table),改变虚拟地址到物理地址的映射。
  • 切换地址空间,加载新进程的内存布局。
  • 可能导致 TLB(Translation Lookaside Buffer) 被刷新,影响性能。
  • 切换文件描述符、信号掩码等进程级资源。
线程切换(Thread Switch)
  • 保存当前线程的栈指针、程序计数器、寄存器等执行状态。
  • 加载目标线程的执行状态。
  • 不切换地址空间,因为所有线程共享同一进程的内存。

线程切换为什么比进程切换快,节省了什么资源?

线程切换比进程切换快是因为线程共享同一进程的地址空间和资源,线程切换时只需切换堆栈和程序计数器等少量信息,而不需要切换地址空间,避免了进程切换时需要切换内存映射表等大量资源的开销,从而节省了时间和系统资源。

资源/操作 进程切换 线程切换 节省效果
地址空间(虚拟内存) ✅ 必须切换 ❌ 无需切换(共享) ⭐⭐⭐⭐⭐ 巨大节省
页表(Page Table) ✅ 切换并加载新页表 ❌ 不切换 ⭐⭐⭐⭐⭐
TLB(快表) ✅ 通常需刷新或失效 ❌ 大部分可保留 ⭐⭐⭐⭐ 提升缓存命中率
CPU 缓存(Cache) ✅ 容易失效(访问不同内存) ✅ 更可能命中(共享数据) ⭐⭐⭐ 提升性能
文件描述符表 ✅ 切换 ❌ 共享,不切换 ⭐⭐
信号处理上下文 ✅ 切换 ❌ 共享
寄存器和栈 ✅ 保存/恢复 ✅ 保存/恢复 ❌ 无节省(必须操作)
1. 地址空间和页表切换开销大
  • 每个进程有独立的虚拟地址空间,操作系统通过页表将虚拟地址映射到物理地址。
  • 切换进程时,CPU 必须加载新进程的页表基址(如 x86 的 CR3 寄存器)。
  • 这是一个昂贵的内核操作,涉及内存访问和 CPU 特权指令。
2. TLB 刷新导致性能下降
  • TLB(Translation Lookaside Buffer) 是 CPU 中的高速缓存,用于加速虚拟地址到物理地址的转换。
  • 进程切换后,旧的 TLB 条目对新进程无效,必须刷新或标记为无效
  • 后续内存访问会TLB Miss,需要查页表,导致显著延迟(几十到上百个时钟周期)。
3. CPU 缓存失效
  • 进程切换后,新进程访问的内存数据通常不在 CPU 缓存中,导致大量缓存 Miss,需要从主存加载,速度慢。
  • 线程切换由于共享内存,缓存中的数据更可能被重复使用,局部性好

线程切换上下文保存在哪里?

线程的上下文(Context)保存在 线程控制块(Thread Control Block, TCB) 中。

什么是 TCB?

  • TCB 是操作系统为每个线程维护的一个内核数据结构。
  • 它包含了线程的所有运行时状态信息。

TCB 中保存的主要内容

类别 具体内容
寄存器上下文 ✅ 程序计数器(PC)、栈指针(SP)、通用寄存器、状态寄存器等(切换时直接用)
线程状态 NEW, RUNNABLE, BLOCKED, WAITING, TERMINATED
调度信息 优先级、调度策略、时间片剩余量
栈信息 用户栈和内核栈的起始地址、大小
指向进程的指针 所属进程的 PCB(Process Control Block)
同步信息 等待的锁、信号量、条件变量等
其他 线程 ID(TID)、打开的文件描述符(共享进程的)、信号掩码等

进程间通讯有哪些方式?

方式 说明 特点
1. 管道(Pipe) 半双工通信,数据单向流动 简单、常用,但只能用于有亲缘关系的进程
2. 命名管道(Named Pipe / FIFO) 有名字的管道,可在无亲缘关系进程间使用 比普通管道更灵活
3. 信号(Signal) 异步通知机制,用于事件通知 轻量,但只能传递简单信息(如 SIGTERM
4. 消息队列(Message Queue) 存储消息的链表,由内核管理 可跨进程、持久化、支持优先级
5. 共享内存(Shared Memory) 多个进程共享同一块物理内存 最快的 IPC 方式,但需同步控制(如信号量)
6. 信号量(Semaphore) 用于进程间同步,控制对共享资源的访问 不是通信方式,而是同步机制
7. 套接字(Socket) 网络或本地进程间通信 支持跨主机通信,功能强大
8. 文件(File) 通过读写文件交换数据 简单但效率低,易冲突
管道(Pipe)
  • 类型:匿名管道(Anonymous Pipe)
  • 特点
    • 半双工:数据只能单向传输
    • 只能在父子进程或兄弟进程 之间使用(通过 fork() 创建)。
    • 生命周期随进程结束而销毁。
命名管道(FIFO)
  • 特点
    • 有名字的管道,可在任意进程间使用。
    • 类似文件,通过路径名访问(如 /tmp/myfifo)。
    • 仍为半双工。
  • 优点:突破了亲缘关系限制。
  • 创建mkfifo("myfifo", 0666);
信号(Signal)
  • 作用:通知进程发生了某个事件(如中断、错误、终止)。
  • 常见信号SIGINT(Ctrl+C)、SIGTERM(终止)、SIGKILL(强制终止)
  • 特点
    • 异步:接收方无法预测何时收到。
    • 只能传递通知 ,不能传数据(除 siginfo_t 外)。
  • 使用kill()signal()sigaction()
消息队列(Message Queue)
  • 特点
    • 消息带有类型,可选择性读取。
    • 消息保存在内核中,直到被读取。
    • 支持多个进程读写。
  • 优点:比管道更灵活,支持优先级和随机读取。
  • 系统调用msgget()msgsnd()msgrcv()msgctl()
共享内存(Shared Memory)
  • 特点
    • 最快的 IPC 方式,因为数据不需要在进程间复制。
    • 多个进程将同一块物理内存映射到各自的地址空间。
    • 需配合信号量或互斥锁使用,防止竞态条件。
  • 系统调用shmget()shmat()shmdt()shmctl()
  • 使用场景:高性能数据交换,如数据库、实时系统。
. 信号量(Semaphore)
  • 作用同步机制,不是通信方式。
  • 用途:控制多个进程对共享资源(如共享内存)的访问,防止冲突。
  • 类型:二元信号量(0/1)、计数信号量。
  • 常与共享内存配合使用
套接字(Socket)
  • 类型
    • 本地套接字(Unix Domain Socket):同一台机器上的进程通信,效率高。
    • 网络套接字(TCP/UDP):跨主机通信。
  • 优点
    • 支持双向通信。
    • 跨平台、跨语言。
    • 可扩展性强。
  • 使用场景:Web 服务器(Nginx ↔ PHP)、微服务通信
文件(File)
  • 方式:进程 A 写文件,进程 B 读文件。
  • 缺点
    • 速度慢(涉及磁盘 I/O)。
    • 需要处理并发读写冲突(如加文件锁)。
    • 不实时。
  • 适用场景:简单配置共享、日志记录
  • 父子进程简单通信管道
  • 任意本地进程通信命名管道、消息队列、共享内存 + 信号量、Unix 套接字
  • 高性能数据共享共享内存(记得加锁)
  • 跨主机通信Socket(TCP/UDP)
  • 异步事件通知信号、消息队列
  • 微服务架构Socket(HTTP/gRPC)

信号和信号量有什么区别?

信号(Signal) 一种异步通知机制,用于告诉进程或线程"某个事件发生了"。

  • 常见信号

    • SIGINT:用户按下 Ctrl+C,请求中断。
    • SIGTERM:请求终止进程(可被捕获)。
    • SIGKILL:强制终止进程(不可捕获)。
    • SIGSEGV:段错误(访问非法内存)。
    • SIGALRM:定时器超时。
  • 特点

    • 异步:接收方无法预测何时收到。
    • 轻量:只传递一个编号,不带复杂数据。
    • 可捕获或忽略 :大多数信号可以注册处理函数(如 signal()sigaction())。
    • 默认行为:如终止、忽略、暂停等。

信号量(Semaphore) 一个整型计数器 ,用于控制多个进程或线程对共享资源的访问。

  • 两个核心操作

    • P 操作(wait / acquire)
      • 计数器减 1。
      • 如果计数器 < 0,则线程/进程阻塞。
    • V 操作(signal / release)
      • 计数器加 1。
      • 唤醒一个等待的线程/进程。
区别点 信号 信号量
是通知还是同步? 是通知机制 是同步机制
改变状态吗? 不改变资源状态,只通知 改变计数器,控制访问
能用于互斥吗? ❌ 不能 ✅ 能(二元信号量)
能用于协调执行顺序吗? ❌ 不适合 ✅ 可以(如生产者-消费者)
名字中的"信号"含义 "警报信号" "通行信号"

共享内存怎么实现的?

共享内存(Shared Memory)是最快的进程间通信(IPC)方式。

共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中。这样这个进程写入的东西,另外一个进程马上就能看到了,都不需要拷贝来拷贝去,传来传去,大大提高了进程间通信的速度

进程调度算法有哪些?

**先来先服务:**有利于CPU繁忙作业,不利于IO繁忙作业。有利于长作业,不利于短作业。

短作业优先: 优先执行预计运行时间最短的进程,这有助于提高系统的吞吐量。不利于长作业,未考虑作业的紧迫程度;平均等待时间和平均周转时间最少。

**高响应比优先调度算法:**响应比=(服务时间等待时间+服务时间​)/服务时间​。主要是权衡了短作业和长作业。

**时间片轮转调度算法:**用于分时系统,需要选择合适大小的时间片。

**优先级调度算法:**可以设置紧迫程度、参照以下原则设计:系统进程大于用户进程、交互进程大于非交互进程、IO进程大于计算进程。

多级反馈队列调度算法。「时间片轮转算法」和「最高优先级算法」的综合和发展。

  • 「多级」表示有多个队列,每个队列优先级从高到低,同时优先级越高时间片越短。

优点如下:终端型作业,短作业优先;短批处理作业,周转时间短;长批处理作业,经过前几个队列得到部分执行,不会长期不执行。

会产生饥饿的进程调度算法?

短作业优先、优先级调度算法、多级反馈队列调度算法

处理机的三级调度

作业调度(高级调度)、内存调度(中级调度)、进程调度(低级调度)。

**高级调度:**把作业从外存中取出,给它分配内存和其它资源,让它称为一个进程,是其能具备竞争处理机的条件。它是主存和辅存之间的调度。一个作业只调入一次调出一次。

中级调度作用是提高内存利用率和系统吞吐量。将那些不能运行的进程挂起到外存,如果他们已经具备运行条件,有稍微有些空闲,由中级调度决定外存上的进程重新调入内存,并修改为就绪态。

进程调度:是操作系统最基本的调度。按照某种方法和策略从就绪队列中选取一个进程,将处理机分配给它。调度频率非常高。

三者的关系

①作业调度为进程活动做准备,进程调度使进程被执行,中级调度将不能运行的进程挂起,将具备条件的进程设置就绪。

②作业调度、内存调度、进程调度频率递增;

③进程调度使最基本的不能缺少。

同步和互斥? 临界资源和临界区?

1.同步 多个进程因为合作而使得进程的执行有一定的先后顺序。比如某个进程需要另一个进程提供的消息,获得消息之前进入阻塞态;

2.互斥多个进程在同一时刻只有一个进程能进入临界区

3.临界资源:每次只允许一个进程访问的资源称为临界资源。

4.临界区:访问临界资源的那段代码称为临界区

在生产者消费者问题中,实现互斥的p操作一定要在实现同步的p操作之后。

v操作不会导致进程阻塞,因此两个v操作顺序可以交换

同步机制的4个准则

1.空闲让进 :当无进程处于临界区,可允许一个请求进入临界区的进程立即进入自己的临界区

2. 忙则等待 :当已有进程进入自己的临界区,所有企图进入临界区的进程必须等待

3. ****有限等待 :****对要求访问临界资源的进程,应保证该进程能在有限时间内进入自己的临界区

4. ****让权等待 :****当进程不能进入自己的临界区,应释放处理机


死锁

死锁的定义

是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力

作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等

待的进程称为死锁进程。

死锁原因:

① 系统资源不足(对不可剥夺资源的竞争)

② 进程推进顺序不当(P1拥有A申请B,P2拥有B申请A)

产生死锁的必要条件:

****① 互斥条件:****指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。

****② 请求和保持条件:****指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

③ 不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放

****④ 环路等待条件:****指在发生死锁时,必然存在一个进程资源的环形链。

为什么并发执行线程要加锁?

并发执行线程需要加锁主要是为了保护共享数据,防止出现"竞态条件"。

"竞态条件"是指当多个线程同时访问和操作同一块数据时,最终结果依赖于线程的执行顺序,这可能导致数据的不一致性。

通过加锁,我们可以确保在任何时刻只有一个线程能够访问共享数据,从而避免"竞态条件",确保数据的一致性和完整性。

什么是饥饿?与死锁有什么差别?活锁?

概念 定义 关键特征
饥饿(Starvation) 一个或多个线程长期得不到所需资源,导致无法执行。 线程"饿着",但系统仍在运行
死锁(Deadlock) 多个线程互相等待对方释放资源 ,导致全部无法推进 所有相关线程"卡死",系统停滞
活锁(Livelock) 线程没有被阻塞 ,但因不断重试或让步 ,导致无法取得进展 线程在"忙碌"但没做事

饥饿:当线程需要某些资源比如CPU,却始终得不到

饥饿并不代表系统已经死锁,但至少有一个程序的执行被无限期地推迟。

差别

① 进入饥饿的进程可以只有一个,但是死锁必须大于等于两个;

② 出于饥饿状态的进程可以是一个就绪进程,但是死锁状态的进程必定是阻塞进程。

****活锁:****是指线程1可以使用资源,但它很礼貌,让其他线程先使用资源,线程2也可以使用资源,但它很绅士,也让其他线程先使用资源。这样你让我,我让你,最后两个线程都无法使用资源。

描述银行家算法

主要思想是避免系统进入不安全状态,在每次进行资源分配时,它首先检查系统是否有足够的资源满足要求,如果有,则先试行分配,并对分配后的新状态进行安全性检查。如果新状态安全,则正式分配上述资源,否则拒绝分配上述资源。这样就保证系统始终处于安全状态,从而避免死锁现象的发生

乐观锁和悲观锁有什么区别?

对比项 乐观锁 悲观锁
假设 冲突很少发生 冲突经常发生
策略 先操作,提交时检查是否冲突 操作前先加锁,防止冲突
类比 "先干了再说,出问题再重试" "先占住再说,别人别碰"
开销 冲突少时开销小 始终有加锁开销
适用场景 读多写少、低并发 写多、高并发、强一致性

乐观锁:

  • 基本思想:乐观锁假设多个事务之间很少发生冲突,因此在读取数据时不会加锁,而是在更新数据时检检查数据的版本(如使用版本号或时间戳),如果版本匹配则执行更新操作,否则认为发生了冲突。
  • 使用场景:乐观锁适用于读多写少的场景,可以减少锁的竞争,提高并发性能。例如,数据库中的乐观锁机制可以用于处理并发更新同一行数据的情况。

悲观锁:

  • 基本思想:悲观锁假设多个事务之间会频繁发生冲突,因此在读取数据时会加锁,防止其他事务对数据进行修改,直到当前事务完成操作后才释放锁。
  • 使用场景:悲观锁适用于写多的场景,通过加锁保证数据的一致性。例如,数据库中的行级锁机制可以用于处理并发更新同一行数据的情况。

乐观锁适用于读多写少的场景,通过版本控制来处理冲突;而悲观锁适用于写多的场景,通过加锁来避免冲突。

内存管理


介绍一下操作系统内存管理

操作系统内存管理是操作系统的核心功能之一,主要负责合理分配、回收和保护内存资源,确保多个进程能够高效、安全地共享物理内存。

操作系统设计了虚拟内存,每个进程都有自己的独立的虚拟内存,我们所写的程序不会直接与物理内打交道。

内存管理的核心目标

  1. 提高内存利用率:让尽可能多的程序装入内存。
  2. 方便程序使用:为程序员提供"无限大"的地址空间。
  3. 实现内存保护:防止进程非法访问其他进程或系统的内存。
  4. 支持虚拟内存:让程序可以运行在比物理内存更大的"虚拟"空间中。

内存管理的主要技术

1. 程序装入与链接
  • 编译 :源代码 → 目标模块(.o.obj
  • 链接 :多个目标模块 → 可执行文件
    • 静态链接:库代码复制到程序中
    • 动态链接:运行时加载共享库(如 .dll.so
  • 装入 :可执行文件 → 内存
    • 绝对装入:指定固定地址
    • 可重定位装入:允许移动
    • 动态运行时装入:运行时才决定地址
2. 连续分配管理方式

早期系统使用,每个进程占用一块连续的内存区域。

方式 说明
单一连续分配 整个内存只给一个用户程序用(如早期 DOS)
固定分区分配 内存划分为若干固定大小的分区,每个分区放一个进程(浪费严重)
动态分区分配 按需分配,产生"碎片"
伙伴系统(Buddy System) Linux 使用的算法,按 2 的幂次分配,减少碎片
3. 非连续分配管理方式(现代主流)

允许一个进程的内存分布在多个不连续的物理块中。

(1)分页(Paging)
  • 将物理内存划分为固定大小的页框(Page Frame,如 4KB)。
  • 将进程的逻辑地址空间划分为(Page)。
  • 通过页表(Page Table) 建立"逻辑页号 → 物理页框号"的映射。
  • 优点
    • 消除外部碎片
    • 易于管理
  • 缺点
    • 存在内部碎片(最后一页可能不满)
    • 页表占用内存
(2)分段(Segmentation)
  • 按逻辑单位划分内存(如代码段、数据段、堆、栈)。
  • 每个段大小可变,有段名和长度。
  • 通过段表进行地址转换。
  • 优点
    • 符合程序结构
    • 便于共享和保护
  • 缺点
    • 产生外部碎片
    • 管理复杂
(3)段页式管理
  • 结合分段和分页的优点。
  • 先分段,再将每段分成页。
  • 地址 = 段号 + 页号 + 页内偏移
  • 现代操作系统(如 x86)常采用此方式。
4. 虚拟内存(Virtual Memory)
  • 核心思想把硬盘当内存用,让程序感觉有"巨大"的内存空间。
  • 实现技术
    • 请求分页(Demand Paging):只加载当前需要的页,其余在磁盘上。
    • 页面置换(Page Replacement):内存满时,换出不常用的页(算法:FIFO、LRU、Clock 等)。
    • 写时复制(Copy-on-Write):多个进程共享页面,写时才复制。
  • 好处
    • 运行比物理内存大的程序
    • 提高并发度(更多进程可装入)
    • 简化链接和装入
5. 地址转换(MMU + TLB)
  • MMU(Memory Management Unit) :硬件单元,负责将逻辑地址 转换为物理地址
  • TLB(Translation Lookaside Buffer):高速缓存,缓存最近使用的页表项,加快地址转换速度。

什么是虚拟内存和物理内存?

|----------|---------------------------------------------------|
| 物理内存 | 计算机中实际存在的 RAM(随机存取存储器),是硬件层面的真实内存。 |
| 虚拟内存 | 操作系统为每个进程提供的 "假想的、连续的" 地址空间,它比物理内存大,可以包含硬盘空间。 |

虚拟地址是怎么转化到物理地址的?

虚拟地址(Virtual Address)转换为物理地址(Physical Address)是操作系统内存管理的核心机制,主要由 硬件(MMU)和软件(操作系统)协同完成 ,通过 分页(Paging)页表(Page Table) 实现。

组件 作用
MMU(Memory Management Unit) CPU 内的硬件单元,负责自动完成地址转换
页表(Page Table) 操作系统维护的映射表,记录"虚拟页 → 物理页框"的对应关系
TLB(Translation Lookaside Buffer) 高速缓存,缓存最近使用的页表项,加速转换

将用户程序变为可在内存中执行的程序的步骤?

1.编译:由编译程序将用户源代码编译成若干目标模块

2. 链接:由链接程序将编译后形成的一组目标模块及所需的库函数链接在一起,形成一个完整的装入模块。

3. 装入 :由装入程序将装入模块装入内存中运行。

程序的链接方式有哪些?

① 静态链接:在程序运行之前,先把各个目标模块及所需库链接为一个完整的可执行程序,以后

不再拆开。

② 装入时动态链接:将应用程序编译后所得到的一组目标模块在装入内存时采用边装入边链接的

链接方式。

③ 运行时动态链接:知道程序运行过程中需要一些模块时,才对这些模块进行链接。

页面置换有哪些算法?

**最佳页面置换算法:**置换在「未来」最长时间不访问的页面。

先进先出置换算法选择在内存驻留时间很长的页面进行中置换,这个就是「先进先出置换」算法的思想。

最近最久未使用的置换算法: 发生缺页时,选择最长时间没有被访问的页面进行置换,也就是说,该算法假设已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。

时钟(CLOCK)置换算法:

最不常用算法:当发生缺页中断时,选择「访问次数」最少的那个页面,并将其淘汰

相关推荐
oak隔壁找我11 分钟前
Spring AI 入门教程,使用Ollama本地模型集成,实现对话记忆功能。
java·人工智能·后端
懒羊羊不懒@11 分钟前
JavaSe—Stream流☆
java·开发语言·数据结构
郝开12 分钟前
最终 2.x 系列版本)2 - 框架搭建:pom配置;多环境配置文件配置;多环境数据源配置;测试 / 生产多环境数据源配置
java·spring boot·后端
Js_cold26 分钟前
(* clock_buffer_type=“NONE“ *)
开发语言·fpga开发·verilog·vivado·buffer·clock
Homeey33 分钟前
深入理解ThreadLocal:从原理到架构实践的全面解析
java·后端
ANGLAL35 分钟前
27.短链系统
java
周杰伦_Jay38 分钟前
【Go微服务框架深度对比】Kratos、Go-Zero、Go-Micro、GoFrame、Sponge五大框架
开发语言·微服务·golang
杰瑞哥哥1 小时前
标准 Python 项目结构
开发语言·python
shykevin1 小时前
Rust入门
开发语言·后端·rust
QT 小鲜肉1 小时前
【个人成长笔记】将Try Ubuntu里面配置好的文件系统克隆在U盘上(创建一个带有持久化功能的Ubuntu Live USB系统)
linux·开发语言·数据库·笔记·ubuntu