哈工大李治军老师OS课程笔记(4)——内存管理
一 内存使用与分段(实验六)
内存是如何用起来的?
内存使用:将程序放在内存中,PC指向开始地址
重定位:修改程序中的地址(是相对地址)

什么时候完成重定位?
编译时加基址
缺点:编译的时候就得知道哪段内存是空闲的,但是在实际的系统中很难做到,比如编译的时候1000处是空闲的,但是执行的时候就不一定了。
载入时加基址更灵活
- 编译时重定位的程序只能放在内存固定位置
- 载入时重定位的程序一旦载入内存就不能动了
编译是将源代码转换为可执行代码的过程。它包括以下步骤:
1.词法分析:将源代码分解为词法单元(tokens),如标识符、关键字、运算符等。
2.语法分析:根据语法规则将词法单元组织成语法树(syntax tree)。
3.语义分析:检查语法树的语义正确性,进行类型检查和语义规则验证。
4.中间代码生成:生成中间表示形式,如抽象语法树(AST)或中间代码。
5.优化:对中间代码进行优化,提高程序的性能和效率。
6.目标代码生成:将优化后的中间代码转换为目标机器的汇编代码或机器代码。
编译器负责执行以上步骤,将源代码转换为可执行代码或可加载的目标文件。编译产生的目标文件可能包含可执行代码、库函数、符号表等。
加载是将目标文件或可执行代码加载到内存中并执行的过程。它包括以下步骤:
1.内存分配:为程序分配足够的内存空间,包括代码段、数据段、堆和栈等。
2.符号解析:解析目标文件中的符号表,建立符号与内存地址之间的关联。
3.重定位:如果目标文件中存在地址引用,进行地址修正,将相对地址转换为实际的内存地址。
4.加载到内存:将目标文件的代码和数据加载到相应的内存段中。
5.初始化:执行程序的初始化代码,如全局变量的初始化、运行时库的初始化等。
6.执行:跳转到程序的入口点,开始执行程序的指令。
加载器(Loader)负责执行以上步骤,将目标文件加载到内存中并启动程序的执行
重定位最合适的时机——运行时重定位
进程再执行过程中会发生变化,不一定每次执行都放在同一块内存空间,程序的基址存放在PCB中。当一次运行时程序被放在内存1000的位置,PCB中的base为1000,换出再换入到地址2000的地方,PCB中的base为2000。执行指令时第一步 先从PCB中取出这个基地址。基地址加上程序中的逻辑地址就得到了这条指令真正的物理地址。

找到空闲内存,将这段空闲程序基地址放到PCB中,然后将程序放入空闲内存
分段
在编译过程中,源代码会经过一系列的编译器处理,其中的一个重要步骤是将源代码转换为可执行的机器代码。这个过程中,编译器会将程序按照功能或作用划分为不同的段,通常包括代码段、数据段和堆栈段。
1.代码段(Code Segment):
代码段包含程序的指令(机器代码),用于执行程序的操作。在程序执行时,代码段会被加载到内存中,并按照指令的顺序依次执行。
2.数据段(Data Segment):
数据段存储程序的静态变量和全局变量等数据。这些变量在程序运行过程中会保持不变,存储在数据段中的数据在整个程序执行期间都是可访问的。
3.堆栈段(Stack Segment):
堆栈段用于存储程序执行期间的局部变量、函数调用信息和函数返回地址等。每当程序调用函数或进入一个新的作用域时,相关的数据会被压入堆栈中,当函数返回或作用域结束时,相关数据会被弹出。堆栈的管理由程序在运行时负责
分段符合用户观点:用户可独立考虑每个段(分治)


操作系统对应的段表就是GDT表,每个进程对应的段表是LDT表。段表形式如下图所示:

把程序分成多个段,在内存中找到空闲的地方,把段放进去,记录这个段在内存中的基址放入LDT表,把LDT表中赋给PCB,将PC指针设为程序初值,每次取值执行都去查LDT表,根据LDT表找到该条指令的基址,再加上程序中的偏移地址获得该条指令的物理地址。
内存使用三部走:分段+找空闲分区+映射表
二、内存分区与分页
1、内存分区
一个程序分成多个段(编译干的事儿),在内存中找到一个空闲区域(算法数据结构),通过磁盘读写把程序载入进来(设备驱动),建立映射表和PCB关联(进程管理)

如何找出一段空闲的分区?内存怎么分割?
可变分区的管理过程

首先适配(350,150)速度快 O(1)
最佳适配(200,50) 碎片多
最差适配(350,150)O(n)
2、内存分页
物理内存要使用分页
内存碎片太太多,将空闲分区合并,这个时候需要移动内存,这个操作叫内存紧缩,在这个过程中,计算机中其他进程也无法运行。内存紧缩需要花费大量的时间,如果复制速度1M/1秒,则1G内存的紧缩时间为1000秒。内存紧缩管理内存碎片太消耗时间了,在实际情况中不可行。
让面包没有谁都不想要的碎末——将面包分成片,类比可以将内存分成页。
内存分页
针对每个段的内存请求,系统一页一页的分配给这给段。

将每个段分页,并编页号,将每页放入空闲的页面中,并将页框号与段页号的对应关系放入页表中,当CPU取值执行时,根据页表和程序中的偏移地址找到该条指令的物理地址。

通常,计算机存储中的 “K” 表示 1024,即 1K = 1024 字节。因此,12K 表示 12 * 1024 字节,即 12,288 字节。接下来,将 12,288 转换为十六进制。12,288 的十六进制表示为 0x3000。因此,将 12K 转换为十六进制为 0x3000。
三、多级页表与快表
32位地址空间+4K页面+页号必须连续 => 2^20个页表项 => 大页表占用内存,造成浪费。
如果用一个变量标识该页有没有使用,用到的逻辑页才有页表项,页表中的页号不连续,就需要比较、查找、折半,降低效率。如果页表连续,只需要一次查找就能找到需要的页。
既要连续又要让页表占用内存少,怎么办?
多级页表 页目录表+页表

多级页表提高了空间效率,使用快表提高效率
四、 段页结合的内存管理
段页同时存在:段面向用户/页面向硬件。虚拟内存是一块地址空间
页表是一个数据结构,用于存储虚拟地址和物理地址之间的映射关系。页表中的每一项存储了一个虚拟页号到物理页框号的映射。

虚拟内存是计算机操作系统中的一种技术,它提供了一种抽象的、相对较大的内存空间,使得程序可以访问比物理内存更大的地址空间。虚拟内存的主要目的是扩展计算机系统的内存容量,使得运行大型程序和处理大量数据时更加高效。它通过将物理内存和硬盘上的存储空间结合起来,创建一个逻辑上连续且更大的地址空间供程序使用。
在虚拟内存的机制下,每个程序都被分配了一块连续的虚拟内存空间,该空间被划分为固定大小的块,称为页面(或页)。物理内存也被划分为与页面大小相同的块,称为物理页面(或页框)。当程序需要访问虚拟内存中的某个页面时,操作系统会将该页面从硬盘加载到物理内存中的一个空闲页框中,并建立虚拟内存与物理内存之间的映射关系。虚拟内存的使用带来了以下几个主要的好处:
1.内存扩展:虚拟内存使得程序能够使用比实际物理内存更大的地址空间,从而能够运行更大的程序或处理更多的数据。
2.内存隔离:每个程序都有自己独立的虚拟内存空间,相互之间不会干扰。这提供了更好的安全性和稳定性,一个程序的崩溃不会影响其他程序的运行。
3.虚拟内存管理:操作系统负责管理虚拟内存和物理内存之间的映射关系,根据程序的需求进行页面的加载和卸载。它可以将不常用的页面置换(交换)到硬盘上,从而释放物理内存供其他程序使用。
4.内存保护:虚拟内存允许操作系统为每个页面设置访问权限,例如只读、读写、执行等。这样可以防止程序对其它程序或操作系统的内存空间进行非法访问。
地址翻译

段页式内存下程序如何载入内存:
- 找到空闲段
- 把段程序“假装”放在虚拟内存上,建立段表
- 在物理内存中找空闲页
- 建立页表
- 利用重定位使用内存
五、 内存换出换出
1、内存换入——请求调页
没有换入换出,虚拟内存实现不了。
用换入换出实现“大内存”

假设虚拟内存有4G大小,但是对应的实际物理内存只有1G大小,如何给用户大内存的感觉呢?

将虚拟内存比作仓库,物理内存比作门店
缺页引起内存的换入
2、内存换出
算法评价准则:缺页次数
(1)FIFO
(2)MIN算法
选择最远将使用的页淘汰
(3)LRU页面置换
用过去的历史预测将来。LRU:选最近最长一段时间没有使用的页淘汰(最近最少使用)。
实现方法
- 时间戳,每页维护一个时间戳,选具有最小时间戳页淘汰。
缺点:每次地址访问都需要修改时间戳,需要维护一个全局的时钟,找到最小值,实现代价较大。 - 维护一个页码栈

每次地址访问都需要修改栈(修改10次左右栈指针),实现代价大。
LRU近似实现 ——clock算法
相关文章:
哈工大李治军老师OS课程笔记(4)——内存管理
一 内存使用与分段(实验六) 内存是如何用起来的? 内存使用:将程序放在内存中,PC指向开始地址 重定位:修改程序中的地址(是相对地址) 什么时候完成重定位? 编译时加基址…...
代码随想录算法训练营第43天:动态规划part10:子序列问题
300.最长递增子序列 力扣题目链接(opens new window) 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2…...
传智教育引通义灵码进课堂,为技术人才教育学习提效
7 月 17 日,阿里云与传智教育在阿里巴巴云谷园区签署合作协议,双方将基于阿里云智能编程助手通义灵码在课程共建、品牌合作及产教融合等多个领域展开合作,共同推进 AI 教育及相关业务的发展,致力于培养适应未来社会需求的高素质技…...
企业信息化建设搞得好了叫系统工程,搞不好叫面子工程
2024-06-13 09:26贝格前端工场...
程序员如何平衡日常编码工作与提升式学习?
在快速变化的编程领域中,平衡日常编码工作与个人成长确实是一个重要且富有挑战性的议题。以下是我对这一问题的看法和建议: 1. 认识到平衡的重要性 首先,理解两者之间的平衡并非零和游戏,而是相辅相成的。高效的编码工作能够为个…...
Linux---文件系统和日志分析
文章目录 文件系统和日志分析inode和block概述inode包含文件的元信息用stat命令可以查看某个文件的inode信息Linux系统文件三个主要的时间属性 目录文件的结构用户通过文件名打开文件时,系统内部的过程查看inode号码的方法硬盘分区后的结构访问文件的简单流程inode的…...
MySQL 体系架构
文章目录 一. MySQL 分支与变种1. Drizzle2. MariaDB3. Percona Server 二. MySQL的替代1. Postgre SQL2. SQLite 三. MySQL 体系架构1.连接层2 Server层(SQL处理层)3. 存储引擎层1)MySQL官方存储引擎概要2)第三方引擎3࿰…...
跨站脚本攻击漏洞
1.JavaScript JavaScript 是一种脚本,一门编程语言,它可以在网页上实现复杂的功能,网页展现给你的不再是简单的静态信息,而是实时的内容更新,交互式的地图,2D/3D动画,滚动播放的视频等等。 &a…...
RabbitMQ入门与进阶
RabbitMQ入门与进阶 基础篇1. 为什么需要消息队列?2. 什么是消息队列?3. RabbitMQ体系结构介绍4. RabbitMQ安装5. HelloWorld6. RabbitMQ经典用法(工作模式)7. Work Queues8. Publish/Subscribe9. Routing10. Topics 进阶篇1. RabbitMQ整合SpringBoot2. 消息可靠性投递故障情…...
Unity新输入系统 之 InputActions(输入配置文件)
本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正 首先你应该了解新输入系统的基本单位Unity新输入系统 之 InputAction(输入配置文件最基本的单位࿰…...
Linux运维篇-误删/bin,/sbin目录怎么修复系统
这里写自定义目录标题 前言实例挂载镜像,重启系统进入救援模式拷贝镜像系统中的/bin和/sbin目录到原系统重启系统 总结 前言 当你看到这篇文章的时候,你的系统可能已经无法登录,或者正在处于登录状态但是不能执行任何常规的命令,…...
构建高效外贸电商系统的技术探索与源码开发
在当今全球化的经济浪潮中,外贸电商作为连接国内外市场的桥梁,其重要性日益凸显。一个高效、稳定、功能全面的外贸电商系统,不仅能够助力企业突破地域限制,拓宽销售渠道,还能提升客户体验,增强品牌竞争力。…...
Java设计模式:中介者模式详解与最佳实践
Java设计模式:中介者模式详解与最佳实践 1. 引言 在软件开发过程中,特别是复杂系统的构建中,模块间的交互往往成为影响代码质量的重要因素。当模块之间耦合度过高时,系统的维护、扩展和理解成本都会显著增加。为了降低模块之间的…...
Matlab绘制像素风字母颜色及透明度随机变化动画
本文是使用 Matlab 绘制像素风字母颜色及透明度随机变化动画的教程 实现效果 实现代码 如果需要更改为其他字母组合,在下面代码的基础上简单修改就可以使用。 步骤:(1) 定义字母形状;(2) 给出字母组合顺序;(3) 重新运行程序&#…...
C:每日一题:二分查找
1、知识介绍: 1.1 概念: 二分查找是一种在有序数组中查找某一特定元素的搜索算法 1.2 基本思想: 每次将待查找的范围缩小一半,通过比较中间元素与目标元素的大小,来决定是在左半部分还是右半部分继续查找。 举个生…...
python Django中使用ORM进行分组统计并降序排列
python Django中使用ORM进行分组统计并降序排列 # 使用supplier和Count进行分组统计,其中supplier为MyModel的一个字段 supplier_counts MyModel.objects.values(supplier).annotate(countCount(supplier)).order_by(-count) # 输出统计结果 for supplier_count in supplier_…...
QT C++ 编写modbus 总结
[开源库的使用]libModbus编译及使用_libmodbus库-CSDN博客 libmodbus的下载与编译_modbus库文件下载-CSDN博客 【QT5】解决 QT 界面中文显示乱码问题_qt5输出中文乱码解决方法-CSDN博客 Qt:解决qt修改完ui文件起不到作用_qt ui文件修改后不生效-CSDN博客...
基于SpringBoot的网络海鲜市场系统的设计与实现
TOC springboot219基于SpringBoot的网络海鲜市场系统的设计与实现 绪论 1.1 选题背景 当人们发现随着生产规模的不断扩大,人为计算方面才是一个巨大的短板,所以发明了各种计算设备,从结绳记事,到算筹,以及算盘&…...
c#相关基础知识
c#参数4种种别 值参:像Java的正常数据的传输 ref:对参数的指向是参数本身的地址,而不是数据的副本,所以可以对数据进行直接操作 out: 绑定控件,控件传输值赋值给类中的内部类 待定...
注意力机制 — 它是什么以及它是如何工作的
一、说明 注意力机制是深度学习领域的一个突破。它们帮助模型专注于数据的重要部分,并提高语言处理和计算机视觉等任务的理解和性能。这篇文章将深入探讨深度学习中注意力的基础知识,并展示其背后的主要思想。 二、注意力机制回顾 在我们谈论注意力之前&…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...
