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内核--内存管理(二)
一.进程与内存 所有进程(执行的程序)都必须占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等.不过进程对这些内存的管理方式因内存用途不一而不尽相同,有些内 ...
随机推荐
- 线性期望(BUPT2015校赛.F)
将整体期望分成部分期望来做. F. network 时间限制 3000 ms 内存限制 65536 KB 题目描述 A social network is a social structure mad ...
- hdu1174(3维射线与圆是否相交)
简单的题意,要注意z2 = h2*0.9-r2 #include <iostream> #include <cmath> #include <vector> #in ...
- django注册在使用hashlib对密码加密时报Unicode-objects must be encoded before hashing
在使用sh1等hashlib方法进行加密时报:Unicode-objects must be encoded before hashing 解决办法:对要加密的字符串指定编码格式 解决之前: s1=s ...
- 六百字读懂 Git(转)
add by zhj:还是原文 六百字读懂 Git 看着更舒服一些,显示更好 原文:六百字读懂 Git 英文原文:Git in 600 words 译注:来自 Hacker School 的 Mary ...
- Java 线程控制(输出奇偶数)
两个线程,一个输出1,3,5,7......99:另一个输出2,4,6,8......100. 1.线程同步 public class ST2 { int i = 0; public static v ...
- Maven学习笔记—仓库
Maven仓库 1 什么是Maven仓库 在Maven中,任何一个依赖.插件或者项目构建的输出,都可以成为构件,而Maven通常在某个位置统一的存储所有Maven项目共享的构件,这个统一的位置就是Ma ...
- Java基础—类和对象
基本概念 对象:对象是类的一个实例,有状态和行为.例如,一条狗是一个对象,它的状态有:颜色.名字.品种:行为有:摇尾巴.叫.吃等. 类:类是具有相同属性和方法的一组对象的集合,它为属于该类的所有对象提 ...
- 003 F-47创建预付定金请求检查增强-20150819.docx
Enhancement SE38:LEINRF26 操作F-47,预付定金请求回车时,检查输入的采购订单项目发票视图,预付定金% 栏位,若为空,则报错,不为空可继续. 检查逻辑:检查采购凭证项 ...
- python并发编程之多线程2---(死锁与递归锁,信号量等)
一.死锁现象与递归锁 进程也是有死锁的 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用, 它们都将无法推进下去.此时称系统处于死锁状态或系统 ...
- input date 对 placeholder 的支持问题
正常情况下,text 的 input 会显示 placeholder 中的值,date 类型的 input 对其支持不好.实例代码如下: <input type="text" ...