Linux 内核开发 - 进程空间
1.1 虚拟内存
Linux 的系统。假设每一个任务都独立的占用内存,则实际的物理内存将非常快消耗殆尽。实际上对于前台正在执行的任务来说,所须要要的内存并不多,非常多任务基本不须要执行,也就没有必要一直占用内存,虚拟内存技术採用硬盘来充当一部分内存,当内存不足时就将不须要在内存中使用的数据搬移到硬盘中去,当任务须要执行时又将硬盘中的数据搬回物理内存。
虚拟内存技术不仅起到了保护操作系统的作用,并且使得用户程序能够使用到比实际物理内存更大的地址空间,屏蔽了实际物理内存对用户地址空间的影响。
1.2 地址空间的划分
对于一个进程而言,Linux 系统将虚拟地址空间划分为用户空间与内核空间,用户空间占用3G(0x0~0xBFFFFFFF),而内核空间占用1G(0xC0000000 ~ 0xFFFFFFFF)。
Linux 是一个多用户的系统,每一个用户就是一个进程,享有独立的地址空间,可是它们是共享内核空间。不同的进程之间进行切换的时候,内核空间的是不变的。
1.3 用户空间
Linux 应用程序时在用户空间执行,仅仅有当产生中断或者当出现系统调用的时候进程才会从用户态切换到内核态。
完毕中断操作或者系统调用后又回到用户态。
1.4 内核空间
Linux 的核心程序执行在内核空间,这是为了保护核心程序不受劣质应用程序的影响而崩溃,并且能起到保护数据的作用。
由于应用程序不具有直接控制硬件的权限,仅仅有内核程序才干拥有系统的最高权限。
1.5 内核内存的分配与释放
在创建进程fork()、动态非配内存malloc()时分配的内存都仅仅是虚拟内存。而不是物理内存,之后在实际訪问分配的虚拟地址时,才会由“请页机制”产生“缺页”异常。进入实际分配页框的程序。
“缺页”异常是是虚拟内存赖以生存的基础。他会告诉内核为进程分配物理页。并建立页表。这时虚拟地址才映射到实际的物理地址。
在应用程序中,使用的是malloc来动态分配内存,而在内核中使用的是kmalloc来分配内存,kmalloc的原型是
#include<linux/slab.h>
#include<linux/gfp.h>
void *kmalloc(size_t size , int flags);
參数:
size:须要分配内存的大小
flags:分配标志。控制kmalloc的行为
下面是flages 可能的标志。
最经常使用的GFP_KERNEL,他表示内存分配(终于总是调用get_free_pages来实现实际的分配,这就是,这就是GFP前缀的由来)是代表执行在内核空间的进程执行的。
使用GFP_KERNEL容许kmalloc在分配空暇内存时候假设内存不足容许把当前进程睡眠以等待。因此这时分配函数必须是可重入的。
假设在进程上下文之外如:中断处理程序、tasklet以及内核定时器中这样的情况下current进程不该睡眠。驱动程序该使用GFP_ATOMIC。
- lGFP_ATOMIC
用来从中断处理和进程上下文之外的其它代码中分配内存. 从不睡眠.
- GFP_KERNEL
内核内存的正常分配. 可能睡眠.
- GFP_USER
用来为用户空间页来分配内存; 它可能睡眠.
- GFP_HIGHUSER
如同 GFP_USER, 可是从高端内存分配, 假设有. 高端内存在下一个子节描写叙述.
- GFP_NOIO
类似 GFP_KERNEL。但禁止不论什么 I/O 初始化
- GFP_NOFS
类似 GFP_KERNEL,但不同意运行不论什么文件系统调用
- __GFP_DMA
这个标志要求分配在可以 DMA 的内存区. 确切的含义是平台依赖的而且在以下章节来解释.
- __GFP_HIGHMEM
这个标志指示分配的内存能够位于高端内存.
- __GFP_HIGH
这个标志标识了一个高优先级请求, 它被同意来消耗甚至被内核保留给紧急状况的最后的内存页.
- __GFP_REPEAT
当它有困难满足一个分配. __GFP_REPEAT 意思是" 更尽力些尝试" 通过反复尝试 -- 可是分配可能仍然失败
- __GFP_NOFAIL
告诉分配器不要失败; 它尽最大努力来满足要求. 使用 __GFP_NOFAIL 是强烈不推荐的
- __GFP_NORETRY
告知分配器马上放弃假设得不到请求的内存.
1.6 按页分配与释放
假设内核模块须要分配大块内存,使用面向页的分配技术会更好。
#include<linux/gfp.h>
- get_zeroed_page(unsigned int flags)
返回新页面的指针,并将页面清零。
- __get_free_page(unsigned int flags);
申请一个页面,返回新页面的指针,但不清零页面。
- __get_free_pages(unsigned int flags ,unsigned int order)
分配并返回一个纸箱内存区第一个字节的指针,内存区可能是一个或者多个页长,可是没有清零(物理上连续)。
order 是你在请求的或释放的页数的以 2 为底的对数(即, log2N). 比如, 假设你要一个页 order 为 0, 假设你请求 8 页就是 3. 假设 order 太大(没有那个大小的连续区可用), 页分配失败. get_order 函数, 它使用一个整数參数, 能够用来从一个 size 中提取 order(它必须是 2 的幂)给主机平台. order 同意的最大值是 10 或者 11 (相应于 1024 或者 2048 页), 依赖于体系. 可是, 一个 order-10 的分配在除了一个刚刚启动的有非常多内存的系统中成功的机会是小的。
- void free_pages(unsigned long addr , unsigned long order);
释放释放的页内存。
- void free_page(unsigned long addr);
释放释放的页内存。须要注意的是假设释放的系统内存与分配的内存不一致会导致系统错误。
1.7 内核空间的内存分布
内核空间是有内核进行映射的,它不会跟着进程变化,是固定的。
什么是高端内存:
在x86结构中。内核被分为三个区块。区域分布例如以下(Linux 与x86类似):
ZONE_DMA 内存開始的16MB
ZONE_NORMAL 16MB~896MB
ZONE_HIGHMEM 896MB ~ 结束
896M以上被称为高端内存,896M下面被称为低端内存。
- 直接映射区(Direct Memory Region)
从0xC0000000(3G)開始的最多896的内存区域被称作直接映射区,这是由于该区域的线性地址和物理存在直接的线性转换关系:
线性地址 = 0xc0000000 + 物理地址
比方物理地址为0x100000 ~ 0x200000 的线性地址就是0xc0100000 ~ 0xc0200000
直接映射区的内存能够通过kmalloc直接分配。
- 动态映射区()
该区域的地址通过vmalloc来进行分配。须要注意的是vmalloc所分配出内存区的线性地址连续,可是物理内存区域是不一定是连续的。它是通过页表的方式将各个空暇的页连接起来使用,所以效率要比kmalloc 要低非常多。
只是vmalloc所分配出来的地址可能出于高端内存、也可能出于低端内存。
- 永久内存映射区(PKMap Region)
该区域可訪问高端内存。訪问方法是使用alloc_page(_GFP_HIGHMEM)分配高端内存页或者使用kmap函数将分配到的高端内存映射到该区域。
永久映射区经常使用的全局变量:
PKMAP_BASE:永久映射空间的起始地址。
永久映射空间为4M。所以它最多能映射4M/4K=1024个页面。
pkmap_page_table:永久映射空间相应的页文件夹。我们来看一下它的初始化:
pkmap_page_table = pte_offset_kernel(pmd_offset(pgd_offset_k
(PKMAP_BASE), PKMAP_BASE), PKMAP_BASE);
实际上它就是PKMAP_BASE所在的PTE
LAST_PKMAP:永久映射空间所能映射的页面数。在没有开启PAE的情况下被定义为1024
highmem_start_page:高端内存的起始页面
pkmap_count[PKMAP]:每一项用来相应映射区域的引用计数
- 固定映射区(Fixing Mapping Region)
该区域和4G的顶端仅仅有4k的隔离带。其每一个地址项都服务于特定的用途。如ACPI_BASE等。
版权声明:本文博主原创文章,博客,未经同意不得转载。
Linux 内核开发 - 进程空间的更多相关文章
- 如何参与Linux内核开发(转)
本文来源于linux内核代码的Document文件夹下的Hoto文件.Chinese translated version of Documentation/HOWTO If you have any ...
- 嵌入式系统Linux内核开发工程师必须掌握的三十道题(转)
嵌入式系统Linux内核开发工程师必须掌握的三十道题 如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师,试试看! 1) Linux中主要有哪几种内核 ...
- 如何参与linux 内核开发
如果想评论或更新本文的内容,请直接联系原文档的维护者.如果你使用英文 交流有困难的话,也可以向中文版维护者求助.如果本翻译更新不及时或者翻 译存在问题,请联系中文版维护者. 英文版维护者: Gre ...
- 如何参与linux内核开发
如何参与linux 内核开发 如果想评论或更新本文的内容,请直接联系原文档的维护者.如果你使用英文 交流有困难的话,也可以向中文版维护者求助.如果本翻译更新不及时或者翻 译存在问题,请联系中文版维 ...
- 深入Linux内核架构——进程管理和调度(上)
如果系统只有一个处理器,那么给定时刻只有一个程序可以运行.在多处理器系统中,真正并行运行的进程数目取决于物理CPU的数目.内核和处理器建立了多任务的错觉,是通过以很短的间隔在系统运行的应用程序之间不停 ...
- 嵌入式Linux内核开发工程师必须掌握的三十道题
如果你能正确回答以下问题并理解相关知识点原理,那么你就可以算得上是基本合格的Linux内核开发工程师. 1. Linux中主要有哪几种内核锁?(进程同步与互斥) (1)自旋锁:非睡眠锁 (2)信号量: ...
- 24小时学通Linux内核之进程
都说这个主题不错,连我自己都觉得有点过大了,不过我想我还是得坚持下去,努力在有限的时间里学习到Linux内核的奥秘,也希望大家多指点,让我更有进步.今天讲的全是进程,这点在大二的时候就困惑了我,结果那 ...
- (转)Linux内核之进程和系统调用
Linux内核之进程和系统调用 什么是系统调用 在Linux的世界里,我们经常会遇到系统调用这一术语,所谓系统调用,就是内核提供的.功能十分强大的一系列的函数.这些系统调用是在内核中实现的,再通过一定 ...
- 编码风格——linux内核开发的coding style
总结linux内核开发的coding style, 便于以后写代码时参考. 下面只是罗列一些规则, 具体说明可以参考: 内核源码(Documentation/CodingStyle) 01 - 缩进 ...
随机推荐
- 全世界最详细的图形化VMware中linux环境下oracle安装(一)【weber出品必属精品】
安装流程:前期准备工作--->安装ORACLE软件--->安装升级补丁--->安装odbc创建数据库--->安装监听器--->安装EM <前期准备工作> 安装 ...
- JDBC 异常特殊原因 (数据库只读解决办法)
JDBC 异常特殊原因 有时候并不是因为程序写的有问题 ,是因为 数据库只读 在sqlserver2005中附加数据库时,附加的数据库会变成只读的,只能进行查询操作. 解决方法: 1 打开Sq ...
- web-打印
项目前景 由于之前的打印是客户端程序,也就是winform做的,现在需要改版成网页版,其他功能都能够很好的实现,就是在打印上遇到一些难点.由于第一次做打印功能,刚开始照搬winform中调用word文 ...
- c++模板编程-typename与class关键字的区别
最近一直在研究c++模板编程,虽然有些困难,但希望能够坚持下去.今天,在书上看见一个讨论模板编程typename与class两个关键字的区别,觉得挺有意义的,就把它们给总结一下. 先看一个例子: te ...
- android 开发中判断网络是否连接的代码
在android的开发中,尤其是与访问网络有关的开发,都要判断一下手机是否连接上了网络,下面是一个判断是否连接网络的嗲吗片段: package cn.com.karl.util; import com ...
- [QT]QT概述
QT概述 基于C++的GUI开发框架,跨平台.Qt 是一个用于桌面系统和嵌入式开发的跨平台应用程序框架. QT是挪威TROLLTECH公司开发的跨平台C++工具,在UNIX下非常出名:他的宗旨是“一次 ...
- CentOS和Ubuntu的区别
CentOS(Community ENTerprise Operating System)是Linux发行版之一,它是来自于Red Hat Enterprise Linux依照开放源代码规定释出的源代 ...
- python学习第一天 -安装配置及其输入输出
Python, 是一种面向对象.解释型计算机程序设计语言. python适合领域: 1.Web网络和各种网络服务 2.系统工具和脚本 3.作为“胶水”语言把其他语言开发的模块包装起来方便使用 pyth ...
- JS 没有块级作用域
在函数(方法)中声明的所有变量,他们在整个函数中都有定义 var scope="abc"; function f() { alert(scope); //显示undefine v ...
- akoj-1140-英雄联盟阵营
英雄联盟阵营 Time Limit:1000MS Memory Limit:65536KTotal Submit:54 Accepted:16 Description 符文之地——瓦罗兰,作为最大的 ...