Linux嵌入式 -- 内核 - 内存管理
1. 逻辑地址 线性地址 物理地址
段式管理: 16位CPU,20根地址总线,可寻址1M内存,但是只有16位的寄存器,64K。
逻辑地址 = 段基地址 + 段内偏移地址
物理地址 PA = 段寄存的值 * 16 + 逻辑地址
段式管理: 32位CPU,两种模式 实模式 + 保护模式
实模式 和 16位CPU一样,段寄存器的值*16就是段地址
保护模式: 段基地址32位,每个段都有4G容量,段寄存器的值是一个选择器,间接指出一个32位的段地址。
页式管理: 线性地址被分为固定长度的组,称为页(page),
例如32位的机器,线性地址最大可为4G,如果用4KB为一个页来划分,这样整个线性地址就被划分为2的20次方个页。
1、分页单元中,页目录的地址放在CPU的cr3寄存器中,是进行地址转换的开始点。
2、每一个进程,都有其独立的虚拟地址空间,运行一个进程,首先需要将它的页目录地址放到cr3寄存器中,将其他进程的保存下来。
3、每一个32位的线性地址被划分为三部份:页目录索引(10位):页表索引(10位):
依据以下步骤进行地址转换:
1、装入进程的页目录地址(操作系统在调度进程时,把这个地址装入CR3)
2、根据线性地址前十位,在页目录中,找到对应的索引项,页目录中的项是一个页表的地址
3、根据线性地址的中间十位,在页表中找到页的起始地址
4、将页的起始地址与线性地址的最后12位相加,得到物理地址偏移(12位)。
Linux内核的设计并没有全部采用Intel所提供的段机制,仅仅是有限度地使用了分段机制。
所有段的基地址均为0
由此可以得出,每个段的逻辑地址空间范围为0-4GB。因为每个段的基地址为0,因此,逻辑地址与线性地址保持一致(即逻辑地址的偏移量字段的值与线性地址的值总是相同的),在Linux中所提到的逻辑地址和线性地址(虚拟地址),可以认为是一致的。看来,Linux巧妙地把段机制给绕过去了,而完全利用了分页机制。
前面介绍了i386的二级页管理架构,不过有些CPU(Alpha 64位)使用三级,甚至四级架构,Linux 2.6.29内核为每种CPU提供统一的界面,采用 了四级页管理架构,来兼容二级、三级、四级管理架构的CPU。
2. 虚拟内存
Linux操作系统采用虚拟内存管理技术,使得每个进程都有独立的进程地址空间,该空间是大小为3G,用户看到和接触的都是虚拟地址,无法看到实际的物理地址。利用这种虚拟地址不但能起到保护操作系统的作用,而且更重要的是用户程序可使用比实际物理内存更大的地址空间。
Linux将4G的虚拟地址空间划分为两个部分——用户空间与内核空间。用户空间从0到0xbfffffff,内核空间从3G到4G。用户进程通常情况下只能访问用户空间的虚拟地址,不能访问内核空间。例外情况是用户进程通过系统调用访问内核空间。
用户空间对应进程,所以每当进程切换,用户空间就会跟着变化。(虚拟地址相同------->页目录页表不同-------> 内存物理地址不同)
创建进程fork()、程序载入execve()、动态内存分配malloc()等进程相关操作都需要分配内存给进程。这时进程申请和获得的不是物理地址,仅仅是虚拟地址。
实际的物理内存只有当进程真的去访问新获取的虚拟地址时,才会由“请页机制”产生“缺页”异常,从而进入分配实际页框的程序。该异常是虚拟内存机制赖以存在的基本保证——它会告诉内核去为进程分配物理页,并建立对应的页表,这之后虚拟地址才实实在在地映射到了物理地址上。
3. 内存分配
在Linux内核中,通常使用kmalloc来动态分配内存。
kmalloc 原型是:
#include <linux/slab.h>
void *kmalloc(size_t size,int flags)
参数:size:要分配的内存大小。flags:分配标志, 它控制 kmalloc 的行为。
GFP_ATOMIC 用来在进程上下文之外的代码(包括中断处理)中分配内存,从不睡眠。
GFP_KERNEL 进程上下文中的分配。可能睡眠。(16M-896M)
__GFP_DMA 这个标志要求分配能够 DMA 的内存区(物理地址在16M以下的页帧 )
__GFP_HIGHMEM 这个标志表示分配的内存位于高端内存。(896M以上)
如果模块需要分配大块的内存,那使用面向页的分配技术会更好
get_zeroed_page(unsigned int flags)
返回指向新页面的指针,并将页面清零。
__get_free_page(unsigned int flags)
和get_free_page类似,但不清零页面。
__get_free_pages(unsigned int flags,unsigned intorder)
分配若干个连续的页面,返回指向该内存区域的指针,但也不清零这段内存区域。
当程序用完这些页, 可以使用下列函数之一来释放它们:
void free_page(unsigned long addr)
void free_pages(unsignedlongaddr, unsigned long order)
**如果释放的和先前分配数目不等的页面,会导致系统错误**
4. 内核空间
内核空间是由内核负责映射,它并不会跟着进程改变,是固定的。物理内存896MB以上的部分称之为高端内存。
直接内存映射区(Direct Memory Region)从3G开始,最大896M的线性地址区间,我们称作直接内存映射区,这是因为该区域的线性地址和物理地址之间存在线性转换关系 线性地址=3G + 物理地址。
动态内存映射区 (Virtual malloc Region)该区域的地址由内核函数vmalloc来进行分配(上图第三条路),其特点是线性空间连续,但对应的物理空间不一定连续。vmalloc分配的线性地址所对应的物理页可能处于低端内存,也可能处于高端内存。
永久内存映射区(PKMap Region )对于896MB以上的高端内存,可使用该区域来访问,访问方法:
1. 使用alloc_page(__GFP_HIGHMEM)分配高端内存页
2. 使用kmap函数将分配到的高端内存映射到该区域。
固定映射区(Fixing MappingRegion)PKMap区上面,有4M的线性空间,被称作固定映射区,它和4G顶端只有4K的隔离带。固定映射区中每个地址项都服务于特定的用途,如ACPI_BASE等。
Linux嵌入式 -- 内核 - 内存管理的更多相关文章
- linux内核--内核内存管理
如题目所示,为什么要称作“内核内存管理”,因为内核所需要的内存和用户态所需要的内存,这两者在管理上是不一样的. 这篇文章描述内核的内存管理,用户态的内存管理在以后的文章中讲述. 首先简单的说明一下下面 ...
- Linux内核内存管理架构
内存管理子系统可能是linux内核中最为复杂的一个子系统,其支持的功能需求众多,如页面映射.页面分配.页面回收.页面交换.冷热页面.紧急页面.页面碎片管理.页面缓存.页面统计等,而且对性能也有很高的要 ...
- Linux内核内存管理算法Buddy和Slab: /proc/meminfo、/proc/buddyinfo、/proc/slabinfo
slabtop cat /proc/slabinfo # name <active_objs> <num_objs> <objsize> <objpersla ...
- linux内核 内存管理
以下内容汇总自网络. 在早期的计算机中,程序是直接运行在物理内存上的.换句话说,就是程序在运行的过程中访问的都是物理地址. 如果这个系统只运行一个程序,那么只要这个程序所需的内存不要超过该机器的物理内 ...
- Linux内核内存管理子系统分析【转】
本文转载自:http://blog.csdn.net/coding__madman/article/details/51298718 版权声明:本文为博主原创文章,未经博主允许不得转载. 还是那张熟悉 ...
- (笔记)Linux内核学习(九)之内核内存管理方式
一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...
- Linux内核学习笔记——内核内存管理方式
一 页 内核把物理页作为内存管理的基本单位:内存管理单元(MMU)把虚拟地址转换为物理 地址,通常以页为单位进行处理.MMU以页大小为单位来管理系统中的也表. 32位系统:页大小4KB 64位系统:页 ...
- Linux内核内存管理
<Linux内核设计与实现>读书笔记(十二)- 内存管理 内核的内存使用不像用户空间那样随意,内核的内存出现错误时也只有靠自己来解决(用户空间的内存错误可以抛给内核来解决). 所有内核 ...
- linux内核--内存管理(二)
一.进程与内存 所有进程(执行的程序)都必须占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等.不过进程对这些内存的管理方式因内存用途不一而不尽相同,有些内 ...
随机推荐
- 【BZOJ2969】矩形粉刷 概率+容斥
[BZOJ2969]矩形粉刷 Description 为了庆祝新的一年到来,小M决定要粉刷一个大木板.大木板实际上是一个W*H的方阵.小M得到了一个神奇的工具,这个工具只需要指定方阵中两个格子,就可以 ...
- coursera 《现代操作系统》 -- 第四周 处理器调度
优先级反转 这往往出现在一个高优先级任务等待访问一个被低优先级任务正在使用的临界资源,从而阻塞了高优先级任务:同时,该低优先级任务被一个次高优先级的任务所抢先,从而无法及时地释放该临界资源.这种情况下 ...
- 剖析与优化 Go 的 web 应用
https://mp.weixin.qq.com/s/HDsbZLOK3h8-XjejvPH2sA https://studygolang.com/articles/12685
- Toeplitz matrix
w https://en.wikipedia.org/wiki/Toeplitz_matrix Proof of Stolz-Cesaro theorem | planetmath.org http ...
- el-tree 设置目录树中的某个节点为高亮状态
现在可以实现,点击某个节点,该节点会红色高亮,那怎么让这个树加载出来的时候 默认某个节点高亮呢?element ui里面带勾选框的可以默认勾选上,这个没有勾选框 其实很简单.element ui的树形 ...
- 安装mysql以及修改初始密码
我们可以采用类似安全模式的方法修改初始密码 先执行命令 mysqld_safe --skip-grant-tables & (设置成安全模式) &,表示在后台运行,不再后台运行的 ...
- LeetCode::Sort List 具体分析
Sort a linked list in O(n log n) time using constant space complexity. 这道题目非常简短的一句话.给链表排序,看到nlogn.我们 ...
- Oracle 11g Enhancements in AWR Baselines
Enhancements in AWR Baselines A baseline is any set of snapshots taken over a period of time. The sn ...
- django目录下的路由系统和视图函数
一.Django路由系统(url) 1.什么是路由系统 路由系统的本质是URL模式以及要为该URL模式调用的视图函数之间的一个映射表即不同的url路径对应的不同的函数,该路由系统是存放在全局配置文件u ...
- python之路 内置函数,装饰器
一.内置函数 #绝对值 abs() #所有值都为真才为真 all() #只要有一个值为真就为真 any() #10进制转成二进制 bin() #10进制转成八进制 oct() #10进制转成十六进制 ...