linux 内存管理

地址类型

一个虚拟内存系统, 意味着用户程序见到的地址不直接对应于硬件使用
的物理地址. 虚拟内存引入了一个间接层, 它允许了许多好事情. 有了虚拟内存, 系统重
运行的程序可以分配远多于物理上可用的内存; 确实, 即便一个单个进程可拥有一个虚拟
地址空间大于系统的物理内存. 虚拟内存也允许程序对进程的地址空间运用多种技巧, 包
括映射成员的内存到设备内存.
至此, 我们已经讨论了虚拟和物理地址, 但是许多细节被掩盖过去了. Linux 系统处理几
种类型的地址, 每个有它自己的含义. 不幸的是, 内核代码不是一直非常清楚确切地在每
个情况下在使用什么类型地地址, 因此程序员必须小心.
下面是一个 Linux 中使用的地址类型列表. 图 Linux 中使用的地址类型显示了这个地址
类型如何关联到物理内存.

                                        Linux 中使用的地址类型

User virtual addresses
这是被用户程序见到的常规地址. 用户地址在长度上是 32 位或者 64 位, 依赖底
层的硬件结构, 并且每个进程有它自己的虚拟地址空间.
Physical addresses
在处理器和系统内存之间使用的地址. 物理地址是 32- 或者 64-位的量; 甚至
32-位系统在某些情况下可使用更大的物理地址.
Bus addresses
在外设和内存之间使用的地址. 经常, 它们和被处理器使用的物理地址相同, 但是
这不是必要的情况. 一些体系可提供一个 I/O 内存管理单元(IOMMU), 它在总线和
主内存之间重映射地址. 一个 IOMMU 可用多种方法使事情简单(例如, 使散布在内
存中的缓冲对设备看来是连续的, 例如), 但是当设定 DMA 操作时对 IOMMU 编程
是一个必须做的额外的步骤. 总线地址是高度特性依赖的, 当然.
Kernel logical addresses
这些组成了正常的内核地址空间. 这些地址映射了部分(也许全部)主存并且常常被
当作它们是物理内存来对待. 在大部分的体系上, 逻辑地址和它们的相关物理地址
只差一个常量偏移. 逻辑地址使用硬件的本地指针大小并且, 因此, 可能不能在重
装备的 32-位系统上寻址所有的物理内存. 逻辑地址常常存储于 unsigned long
或者 void * 类型的变量中. 从 kmalloc 返回的内存有内核逻辑地址.
Kernel virtual addresses
内核虚拟地址类似于逻辑地址, 它们都是从内核空间地址到物理地址的映射. 内核
虚拟地址不必有逻辑地址空间具备的线性的, 一对一到物理地址的映射, 但是. 所有的逻辑地址是内核虚拟地址, 但是许多内核虚拟地址不是逻辑地址. 例如,
vmalloc 分配的内存有虚拟地址(但没有直接物理映射). kmap 函数(本章稍后描述)
也返回虚拟地址. 虚拟地址常常存储于指针变量.

如果你有逻辑地址, 宏 __pa() ( 在 <asm/page.h> 中定义)返回它的关联的物理地址.
物理地址可被映射回逻辑地址使用 __va(), 但是只给低内存页.
不同的内核函数需要不同类型地址. 如果有不同的 C 类型被定义可能不错, 这样请求的
地址类型是明确的, 但是我们没有这样的好运. 在本章, 我们尽力对在哪里使用哪种类型
地址保持清晰.

物理地址和页

物理内存被划分为离散的单元称为页. 系统的许多内部内存处理在按页的基础上完成. 页
大小一个体系不同于另一个, 尽管大部分系统当前使用 4096-字节的页. 常量 PAGE_SIZE
(定义在 <asm/page.h>) 给出了页大小在任何给定的体系上.
如果你查看一个内存地址 - 虚拟或物理 - 它可分为一个页号和一个页内的偏移. 如果使
用 4096-字节页, 例如, 12 位低有效位是偏移, 并且剩下的, 高位指示页号. 如果你丢
弃偏移并且向右移动剩下的部分 offset 位, 结果被称为一个页帧号 (PFN). 移位来在页
帧号和地址之间转换是一个相当普通的操作. 宏 PAGE_SHIFT 告诉必须移动多少位来进行
这个转换.

高和低内存

逻辑和内核虚拟地址之间的不同在配备大量内存的 32-位系统中被突出. 用 32 位, 可能
寻址 4 G 内存. 但是, 直到最近, 在 32-位 系统的 Linux 被限制比那个少很多的内存,
因为它建立虚拟地址的方式.
内核( 在 x86 体系上, 在缺省配置里) 在用户空间和内核之间划分 4-G 虚拟地址; 在 2
个上下文中使用同一套映射. 一个典型的划分分出 3 GB 给用户空间, 和 1 GB 给内核空
间.
[47] 内核的代码和数据结构必须要适合这个空间, 但是内核地址空间最大的消费者是物
理内存的虚拟映射. 内核不能直接操作没有映射到内核的地址空间. 内核, 换句话说, 需
要它自己的虚拟地址给任何它必须直接接触的内存. 因此, 多年来, 能够被内核处理的的
最大量的物理内存是能够映射到虚拟地址的内核部分的数量, 减去内核代码自身需要的空
间. 结果, 基于 x86 的 Linux 系统可以工作在最多稍小于 1 GB 物理内存.
为应对更多内存的商业压力而不破坏 32-位 应用和系统的兼容性, 处理器制造商已经增
加了"地址扩展"特性到他们的产品中. 结果, 在许多情况下, 即便 32-位 处理器也能够
寻址多于 4GB 物理内存. 但是, 多少内存可被直接用逻辑地址映射的限制还存在. 这样
内存的最低部分(上到 1 或 2 GB, 根据硬件和内核配置)有逻辑地址; 剩下的(高内存)没
有. 在存取一个特定高地址页之前, 内核必须建立一个明确的虚拟映射来使这个也在内核
地址空间可用. 因此, 许多内核数据结构必须放在低内存; 高内存用作被保留为用户进程
页.
术语"高内存"对有些人可能是疑惑的, 特别因为它在 PC 世界里有其他的含义. 因此, 为
清晰起见, 我们将定义这些术语:

Low memory
逻辑地址在内核空间中存在的内存. 在大部分每个系统你可能会遇到, 所有的内存
都是低内存.
High memory
逻辑地址不存在的内存, 因为它在为内核虚拟地址设置的地址范围之外.
在 i386 系统上, 低和高内存之间的分界常常设置在刚刚在 1 GB 之下, 尽管那个边界在
内核配置时可被改变. 这个边界和在原始 PC 中有的老的 640 KB 限制没有任何关联, 并
且它的位置不是硬件规定的. 相反, 它是, 内核自身设置的一个限制当它在内核和用户空
间之间划分 32-位地址空间时.
我们将指出使用高内存的限制, 随着我们在本章遇到它们时

内存映射和 struct page

历史上, 内核已使用逻辑地址来引用物理内存页. 高内存支持的增加, 但是, 已暴露这个
方法的一个明显的问题 -- 逻辑地址对高内存不可用. 因此, 处理内存的内核函数更多在
使用指向 struct page 的指针来代替(在 <linux/mm.h> 中定义). 这个数据结构只是用
来跟踪内核需要知道的关于物理内存的所有事情.
2.6 内核(带一个增加的补丁)可以支持一个 "4G/4G" 模式在 x86 硬件上, 它以微弱的性
能代价换来更大的内核和用户虚拟地址空间.
系统中每一个物理页有一个 struct page. 这个结构的一些成员包括下列:
atomic_t count;
这个页的引用数. 当这个 count 掉到 0, 这页被返回给空闲列表.
void *virtual;
这页的内核虚拟地址, 如果它被映射; 否则, NULL. 低内存页一直被映射; 高内存
页常常不是. 这个成员不是在所有体系上出现; 它通常只在页的内核虚拟地址无法
轻易计算时被编译. 如果你想查看这个成员, 正确的方法是使用 page_address 宏,
下面描述.
unsigned long flags;
一套描述页状态的一套位标志. 这些包括 PG_locked, 它指示该页在内存中已被加
锁, 以及 PG_reserved, 它防止内存管理系统使用该页.
有很多的信息在 struct page 中, 但是它是内存管理的更深的黑魔法的一部分并且和驱
动编写者无关.

内核维护一个或多个 struct page 项的数组来跟踪系统中所有物理内存. 在某些系统,
有一个单个数组称为 mem_map. 但是, 在某些系统, 情况更加复杂. 非一致内存存取
( NUMA )系统和那些有很大不连续的物理内存的可能有多于一个内存映射数组, 因此打算
是可移植的代码在任何可能时候应当避免直接对数组存取. 幸运的是, 只是使用 struct
page 指针常常是非常容易, 而不用担心它们来自哪里.
有些函数和宏被定义来在 struct page 指针和虚拟地址之间转换:
struct page *virt_to_page(void *kaddr);
这个宏, 定义在 <asm/page.h>, 采用一个内核逻辑地址并返回它的被关联的
struct page 指针. 因为它需要一个逻辑地址, 它不使用来自 vmalloc 的内存或
者高内存.
struct page *pfn_to_page(int pfn);
为给定的页帧号返回 struct page 指针. 如果需要, 它在传递给 pfn_to_page 之
前使用 pfn_valid 来检查一个页帧号的有效性.
void *page_address(struct page *page);
返回这个页的内核虚拟地址, 如果这样一个地址存在. 对于高内存, 那个地址仅当
这个页已被映射才存在. 这个函数在 <linux/mm.h> 中定义. 大部分情况下, 你想
使用 kmap 的一个版本而不是 page_address.
#include <linux/highmem.h>
void *kmap(struct page *page);
void kunmap(struct page *page);
kmap 为系统中的任何页返回一个内核虚拟地址. 对于低内存页, 它只返回页的逻
辑地址; 对于高内存, kmap 在内核地址空间的一个专用部分中创建一个特殊的映
射. 使用 kmap 创建的映射应当一直使用 kunmap 来释放;一个有限数目的这样的
映射可用, 因此最好不要在它们上停留太长时间. kmap 调用维护一个计数器, 因
此如果 2 个或 多个函数都在同一个页上调用 kmap, 正确的事情发生了. 还要注
意 kmap 可能睡眠当没有映射可用时.
#include <linux/highmem.h>
#include <asm/kmap_types.h>
void *kmap_atomic(struct page *page, enum km_type type);
void kunmap_atomic(void *addr, enum km_type type);
kmap_atomic 是 kmap 的一种高性能形式. 每个体系都给原子的 kmaps 维护一小
列插口( 专用的页表项); 一个 kmap_atomic 的调用者必须在 type 参数中告知系
统使用这些插口中的哪个. 对驱动有意义的唯一插口是 KM_USER0 和 KM_USER1
(对于直接从来自用户空间的调用运行的代码), 以及 KM_IRQ0 和 KM_IRQ1(对于中
断处理). 注意原子的 kmaps 必须被原子地处理; 你的代码不能在持有一个时睡眠.
还要注意内核中没有什么可以阻止 2 个函数试图使用同一个插口并且相互干扰

 尽管每个 CPU 有独特的一套插口). 实际上, 对原子的 kmap 插口的竞争看来不
是个问题.
在本章后面和后续章节中当我们进入例子代码时, 我们看到这些函数的一些使用,

页表

在任何现代系统上, 处理器必须有一个机制来转换虚拟地址到它的对应物理地址. 这个机
制被称为一个页表; 它本质上是一个多级树型结构数组, 包含了虚拟-到-物理的映射和几
个关联的标志. Linux 内核维护一套页表即便在没有直接使用这样页表的体系上.
设备驱动通常可以做的许多操作能涉及操作页表. 幸运的是对于驱动作者, 2.6 内核已经
去掉了任何直接使用页表的需要. 结果是, 我们不描述它们的任何细节; 好奇的读者可能
想读一下 Understanding The Linux Kernel 来了解完整的内容, 作者是 Daniel P.
Bovet 和 Marco Cesati (O' Reilly).

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/305587.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【大厂算法面试冲刺班】day0:数据范围反推时间复杂度

常见算法的时间复杂度 规定n是数组的长度/树或图的节点数 二分查找&#xff1a;O(logn) 双指针/滑动窗口&#xff1a;O(n) DFS/BFS&#xff1a;O(n) 构建前缀和&#xff1a;O(n) 查找前缀和&#xff1a;O(1) 一维动态规划&#xff1a;O(n) 二维动态规划&#xff1a;O(n^2) 回溯…

第7章-第9节-Java中的Stream流(链式调用)

1、什么是Stream流 Lambda表达式&#xff0c;基于Lambda所带来的函数式编程&#xff0c;又引入了一个全新的Stream概念&#xff0c;用于解决集合类库既有的鼻端。 2、案例 假设现在有一个需求&#xff0c; 将list集合中姓张的元素过滤到一个新的集合中&#xff1b;然后将过滤…

做科技类的展台3d模型用什么材质比较好---模大狮模型网

对于科技类展台3D模型&#xff0c;以下是几种常用的材质选择&#xff1a; 金属材质&#xff1a;金属材质常用于科技展台的现代感设计&#xff0c;如不锈钢、铝合金或镀铬材质。金属材质可以赋予展台一个科技感和高档感&#xff0c;同时还可以反射光线&#xff0c;增加模型的真实…

Verilog 高级教程笔记——持续更新中

Verilog advanced tutorial 转换函数 调用系统任务任务描述int_val $rtoi( real_val ) ;实数 real_val 转换为整数 int_val 例如 3.14 -> 3real_val $itor( int_val ) ;整数 int_vla 转换为实数 real_val 例如 3 -> 3.0vec_val $realtobits( real_val ) ;实数转换为…

jquery 合并table表格行或列

合并行 $("#tableId").find("tr").each(function(rowIndex) {var cells $(this).find("td");cells.each(function(cellIndex) {var cell $(this);var prevRowCell table.find("tr:eq(" (rowIndex - 1) ")").find(&quo…

有关“修改地址”的回复话术大全

类型一:不能改地址 1.亲非常抱歉 这边发货后客服就没法帮您操作修改地址了 2.非常遗憾&#xff0c;订单一旦下单完成 地址是无法进行修改的。如果您这边需要修改地址的话也是可以尝试去和这个物流方进行协商的哦&#xff0c;这边没有修改的按钮没法操作的 3.抱歉呢亲亲。修改…

【C语言题解】 | 101. 对称二叉树

101. 对称二叉树 101. 对称二叉树代码 101. 对称二叉树 这个题目要求判断该二叉树是否为对称二叉树&#xff0c;此题与上一题&#xff0c;即 100. 相同的树 这个题有异曲同工之妙&#xff0c;故此题可借鉴上题。 我们先传入需要判断二叉树的根节点&#xff0c;通过isSameTree()…

Java设计模式-访问者模式

访问者模式 一、概述二、结构三、案例实现四、优缺点五、使用场景六、扩展 一、概述 定义&#xff1a; 封装一些作用于某种数据结构中的各元素的操作&#xff0c;它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。 二、结构 访问者模式包含以下主要角色: …

【JAVA】Java8开始ConcurrentHashMap,为什么舍弃分段锁

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 分段锁的好处&#xff1a; 结语 我的其他博客 前言 在Java 8中&#xff0c;ConcurrentHashMap的实现经历了重大的改进&am…

Visual Studio 2017 + opencv4.6 + contribute + Cmake(Aruco配置版本)指南

之前配置过一次这个&#xff0c;想起这玩意就难受&#xff0c;贼难配置。由于要用到里面的一个库&#xff0c;不得已再进行配置。看网上的博客是真的难受&#xff0c;这写一块&#xff0c;那里写一块&#xff0c;乱七八糟&#xff0c;配置一顿发现写的都是错的&#xff0c;还得…

【Python学习】Python学习10-列表

目录 【Python学习】Python学习10-列表 前言创建语法访问列表中的值更新和删除列表元素操作列表列表截取Python列表函数&方法参考 文章所属专区 Python学习 前言 本章节主要说明Python的列表List。 创建语法 创建一个列表 通过方括号和逗号分割创建&#xff0c;列表数据…

一个大场景下无线通信仿真架构思路(对比omnet与训练靶场)

2020年分析过omnet的源码&#xff0c;读了整整一年&#xff0c;读完之后收获不小&#xff0c;但是也遗憾的发现这个东西只适合实验室做研究的人用于协议的研发与测试&#xff0c;并不适合大场景&#xff08;军事游戏等&#xff09;的应用&#xff0c;因为其固有架构更侧重于每个…

视频号小店和抖音小店相比,新手做哪个比较好?

我是电商珠珠 抖音小店在19年被抖音所发展&#xff0c;在这过程中&#xff0c;抖音小店通过自身的不断完善&#xff0c;从兴趣电商到全域兴趣电商模式&#xff0c;从直播电商到商城的出现&#xff0c;凭借着门槛低流量高的优势&#xff0c;让很多商家尝到了红利。 尤其是在20…

1042: 数列求和3 和 1057: 素数判定 和 1063: 最大公约与最小公倍

1042: 数列求和3 题目描述 求1-2/33/5-4/75/9-6/11...的前n项和&#xff0c;结果保留3位小数。 输入 输入正整数n(n>0)。 输出 输出一个实数&#xff0c;保留3位小数&#xff0c;单独占一行。 样例输入 5 样例输出 0.917 #include<stdio.h> int main(){in…

归并排序-排序算法

前言 如果一个数组的左右区间都有序&#xff0c;我们可以使用一种方法&#xff08;归并&#xff09;&#xff0c;使这个数组变得有序。 如下图&#xff1a; 过程也很简单&#xff0c;分别取左右区间中的最小元素&#xff0c;再把其中较小的元素放到临时数组中&#xff0c;例如…

JavaSE学习笔记 2023-12-28 --MySQL

MySQL 个人整理非商业用途&#xff0c;欢迎探讨与指正&#xff01;&#xff01; 文章目录 MySQL1.数据库介绍2.数据库的分类3.数据库中的常用术语4.数据库安装和配置5.MySQL的逻辑结构6.SQL语句7.DML7.1DQL7.1.1基本查询7.1.2过滤查询7.1.2.1条件运算符7.1.2.2逻辑运算符7.1.2.…

Spring 基于注解的AOP见解4

5.基于注解的AOP配置 5.1创建工程 5.1.1.pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation&…

【AI视野·今日NLP 自然语言处理论文速览 第六十七期】Mon, 1 Jan 2024

AI视野今日CS.NLP 自然语言处理论文速览 Mon, 1 Jan 2024 Totally 42 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Principled Gradient-based Markov Chain Monte Carlo for Text Generation Authors Li Du, Afra Amini, Lucas…

基于Springboot的计算机学院校友网(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的计算机学院校友网(有报告)。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring…

红队打靶练习:RICKDICULOUSLYEASY: 1

目录 信息收集 1、arp 2、nmap 3、nikto 4、whatweb 目录探测 gobuster dirsearch WEB get flag1 /robots.txt FTP get flag2 telenet登录 get flag3 get flag4 9090端口 get flag5 dirsearch ssh登录 Summer用户 get flag6 信息收集 get flag7 get fl…