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内核--内存管理(二)
一.进程与内存 所有进程(执行的程序)都必须占用一定数量的内存,它或是用来存放从磁盘载入的程序代码,或是存放取自用户输入的数据等等.不过进程对这些内存的管理方式因内存用途不一而不尽相同,有些内 ...
随机推荐
- 爬虫实战【8】Selenium解析淘宝宝贝-获取多个页面
作为全民购物网站的淘宝是在学习爬虫过程中不可避免要打交道的一个网站,而是淘宝上的数据真的很多,只要我们指定关键字,将会出现成千上万条数据. 今天我们来讲一下如何从淘宝上获取某一类宝贝的信息,比如今天我 ...
- django restframework 的日常使用
本文讨论 django restframework 的日常使用,满足常用 api 编写的需求,比如 List, Detail, Update, Put, Patch 等等.探讨 django rest ...
- window7系统下安装scrapy爬虫框架
本文是在python3.6环境下安装的下面软件,如果大家和我的python版本不一致,请在页面选择符合自己版本的软件下载. 1.wheel pip install wheel 2.lxml 下载lxm ...
- 并发 错误 java.lang.IllegalMonitorStateException: current thread not owner 分析
public class ThreadTest implements Callable<String> { public String call() throws Exception { ...
- WebService中WSDL和WADL(转)
转自https://blog.csdn.net/liuxiao723846/article/details/51611183#commentBox 自己加了修改批注方便自己理解. 1.Java开发We ...
- 使用openresty + lua 搭建api 网关(一)安装openresty ,并添加lua模块
openresty 有点不多说,网上各种介绍,先安装吧. 官方操作在此,http://openresty.org/cn/installation.html, tar -xzvf openresty-V ...
- ABAP 断点篇-001
断点技能不足! 6.2.4 可在调试画面设置break-point.方法:在代码前面双击 6.2.5 为指定语句设置断点方法:(1)选择菜单:Breakpoints->Breakpointat ...
- Redis3.2.8配置参数及说明
bind 127.0.0.1# 绑定的主机地址,不设置默认将处理所有请求protected-mode yes# 是否开启保护模式,默认开启,要是配置里面没有指定bind和密码,开启该参数后,redis ...
- C#数组学习
1.多维数组 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespa ...
- Summaries On Java
@1:== 和 equals(): ==用于比较引用和比较基本数据类型时具有不同的功能: 比较基本数据类型:如果两个值相同,则结果为true. 比较引用:如果引用指向内存中的同一对象,结果为true( ...