一、MMU的基本知识

1.内存管理单元简称mmu,她负责虚拟地址到真实物理地址的转换,并且提供了硬件机制以检查内存

访问权限,同时对Cache缓存进行控制。

2.现代计算机多进程操作系统通过mmu使得各个进程用户都拥有独立的地址空间,从一个进程来看。

都拥有4G(32位cpu)的地址空间,其中0-3G 属于用户空间,3-4G 属于内核空间。

3.各个进程得以正常运行的原因就是mmu提供的内存访问权限检查的硬件机制,她可以保护进程不受

破坏。

4.TTB(Translation Table Base):表示存放在存储器上的页表的地址。

5.TLB(Translation LookasideBuffer):他缓存了少量的虚拟地址到物理地址的转换关系,是地址转

换表的缓存,也称为快表。

6.TTW(Translation Tablewalk):当上面提到的TLB中没有转换关系的时候,那么就需要通过TTW来遍

历存储器上面存储的页表TTB(Translation Table Base).当TTW访问成功后,应该把该结果放入TLB中。

上面这张图很好的阐述了处理器、mmu、存储器之间的框架关系。

下面还有张图,是代码流程图。

二、内存分配函数
1、static inline void *kmalloc(size_t size,gfp_t flags)
/*
size :表示分配的内存大小
通常size大小为一些固定的值,linux内核为size大小提供了如下的取值
32B、64B、128B、256B、512B、1KB、2KB、4KB、8KB、16KB、32KB、64KB、128KB
flags:表示分配标志
通常使用如下标志:
进程上下文,可以睡眠 GFP_KERNEL
进程上下文,不可以睡眠 GFP_ATOMIC
中断处理程序 GFP_ATOMIC
软中断 GFP_ATOMIC
Tasklet GFP_ATOMIC
用于DMA的内存,可以睡眠 GFP_DMA | GFP_KERNEL
用于DMA的内存,不可以睡眠 GFP_DMA | GFP_ATOMIC
*/
1.保证分配的内存在物理上是连续的,虚拟地址上自然也是连续的;
2.当使用DMA访问内存的时候,是要求该片内存在物理上是连续的,所以应该使用该种分配内存方式;
3.void kfree(const void *ptr)释放由kmalloc()分配出来的内存块;
调用流程:

static inline void *kmalloc(size_t size,gfp_t flags)

unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
该函数可分配多个页并返回分配内存的首地址,分配的页数为 2的order次幂,分配的页不清零

struct page * alloc_pages(int gfp_mask, unsigned long order);
该函数返回了分配的第一个页的描述符而非首地址

2、
void *vmalloc(size_t size)

1.保证分配的内存在虚拟上是连续的,物理上不能保证;
2.void vfree(void *addr),这个函数可以睡眠,因此不能从中断上下文调用。
3.vmalloc不能用在原子上下文中, 因为它的内部实现使用了标志为 GFP_KERNEL 的
kmalloc()。
4.vmalloc比 kmalloc要慢 ,因为他调用了kmalloc。
调用流程:
void *vmalloc(size_t size)

static inline void *kmalloc(size_t size,gfp_t flags)

unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
该函数可分配多个页并返回分配内存的首地址,分配的页数为 2的order次幂,分配的页不清零

struct page * alloc_pages(int gfp_mask, unsigned long order);

3、获取某一页在内核中的虚拟地址函数
/**
* page_address - get the mapped virtual address of a page
* @page: &struct page to get the virtual address of
*
* Returns the page's virtual address.
*/
void *page_address(struct page *page)

4、kmalloc、vmalloc和malloc的区别:


[*]kmalloc和 vmalloc 是分配的是内核的内存,malloc分配的是用户的内存 [*]kmalloc保证分配的内存在物理上是连续的,vmalloc保证的是在虚拟地址空间上的连续,malloc不保
证任何东西 (这点是自己猜测的,不一定正确) [*]kmalloc能分配的大小有限,vmalloc和 malloc 能分配的大小相对较大 [*]内存只有在要被DMA 访问的时候才需要物理上连续 [*]vmalloc比kmalloc 要慢 

三、内存分配方法
1.代码实例(按页分配):

#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>#define SWITCH 1struct page *p;
char *s;static int __init mem_test_init(void)
{unsigned long VA,PA;printk("<1>""module init \n"); #if SWITCHp = alloc_pages(GFP_KERNEL,1);  //分配一页if(NULL == p){printk("<1>""alloc pages error ! \n"); return -ENOMEM;   }s = page_address(p);            //获取该页的首地址#elses = (char *)__get_free_pages(GFP_KERNEL,1);     //分配一页,返回该页首地址if(NULL == s){printk("<1>""get free pages error ! \n");return -ENOMEM;    }#endifPA = __pa((unsigned long)s);            //获取s对应的物理地址VA = __va((unsigned long)__va(PA));     //获取s的虚拟地址,注意返回的地址不一定是虚拟地址printk("<1>""s is %p \n",s);printk("<1>""PA is %x \n",PA);printk("<1>""VA is %x \n",VA);  return 0;
}
static void __exit mem_test_exit(void)
{#if SWITCH__free_pages(p, 1);#elsefree_pages((unsigned long)s, 1);#endif     printk("<1>""module exit \n");
}module_init(mem_test_init);
module_exit(mem_test_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("shopping");

当switch等于0时,结果如下:

module init
s is f3c58000
PA is 33c58000
VA is b3c58000

当switch等于1时,结果如下:

module init
s is ea9b8000
PA is 2a9b8000
VA is aa9b8000

很奇怪的是,第一个地址和第三个地址竟然不等?这个问题暂时还没有解决,只能先放一放了。

2.代码实例(kmalloc分配):

#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
char *s;
static int __init mem_test_init(void)
{unsigned long VA,PA;printk("<1>""module init \n"); s = (char*)kmalloc(2,GFP_KERNEL);if(NULL == s){printk("<1>""kmalloc error \n");    return -ENOMEM;   }memcpy(s,"this is mem test",30);printk("<1>""%s \n",s);return 0;
}
static void __exit mem_test_exit(void)
{ kfree(s);printk("<1>""module exit \n");
}module_init(mem_test_init);
module_exit(mem_test_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("shopping");

上面我确实在kmalloc中只分配2字节,但是最终写得时候,还是打印成功了

module init
this is mem test 

这说明该函数确实至少默认分配32字节(这个和架构体系有关)

3.接下来看讨论的最后一种内存分配方式(vmalloc)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
char *s;
static int __init mem_test_init(void)
{unsigned long VA,PA;printk("<1>""module init \n"); s = (char*)vmalloc(30);if(NULL == s){printk("<1>""kmalloc error \n");    return -ENOMEM;   }memcpy(s,"this is mem test",30);printk("<1>""%s \n",s);return 0;
}
static void __exit mem_test_exit(void)
{ vfree(s);printk("<1>""module exit \n");
}module_init(mem_test_init);
module_exit(mem_test_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("shopping");

当指定的size没有真够大的连续空间时,这个函数就会像捡破烂一样,东捡一块西捡一块,凑成满足大
小的物理内存,并连在一起形成连续的虚拟内存再把首地址返回,所以这个函数的操作很麻烦,出于性
能的考虑,能不用的话尽量不用

Linux驱动学习12(初步认识内存管理)相关推荐

  1. Linux驱动学习--android中的内存管理机制ION(一)--简单介绍

    目录 一.引言 二.ION的介绍及使用 ------> ION介绍 ------> ION的使用 ------> HEAP种类 三.接口分析 ------> 主要数据结构 -- ...

  2. Linux驱动学习--android中的内存管理机制ION(二)--ION的使用

    目录 一.引言 二.ION框架 ------> heap类型 ------> ion特性 三.ion的使用 ------> 基本数据结构 ------> 具体的使用 四.ion ...

  3. 嵌入式Linux驱动笔记(二十九)------内存管理之伙伴算法(Buddy)分析

    你好!这里是风筝的博客, 欢迎和我一起交流. 我们知道,在一个通用操作系统里,频繁申请内存释放内存都会出现一个非常著名的内存管理问题:内存碎片. 学过操作系统的都知道,有很多行之有效的方法(比如:记录 ...

  4. IMX6ULL嵌入式Linux驱动学习笔记(二)

    IMX6ULL嵌入式Linux驱动学习 一.字符设备驱动 二.驱动模块的加载与卸载 三.字符设备的注册与注销 四.设备号 五.file_operations的具体实现 六.字符设备驱动框架 七.编写应 ...

  5. ThreadX学习(4)——内存管理

    ThreadX学习(4)--内存管理 学习参考 内存分配 内存字节池 memory byte pool 字节池大小 碎片整理 API 1.tx_byte_pool_create 2.tx_byte_a ...

  6. linux uart寄存器 代替 printk,Linux驱动学习之设备树(设备树下的LED驱动实验),...

    Linux驱动学习之设备树(设备树下的LED驱动实验), 概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.相当于从驱动代码分离出来的配置文件,比如串口的波特率通过设 ...

  7. Linux驱动学习--USB接口wifi/BT芯片开发之BT开发(BlueDroid框架)

    目录 一.引言 二.整体框架分析(结合实际芯片分析) 三.内核中的相关配置 四.厂家驱动分析 五.蓝牙BlueDroid协议 一.引言 之前我们简单分析过BlueDroid框架,今天来结合源码,挑重点 ...

  8. Linux 驱动学习笔记 - beep(九)

    Linux 驱动学习笔记 - beep(九) 本系列均为正点原子 Linux 驱动的学习笔记, 以便加深笔者记忆.如读者想进一步学习,可以到正点原子官网中下载资料进行学习. 添加 pinctrl 节点 ...

  9. Linux 0.12内核的内存管理基础

    在Linux 0.12内核中,为了有效地使用机器中的物理内存,在系统初始化阶段内存被划分成几个功能区域. Linux内核程序占据在物理内存的开始部分,接下来是供硬盘或软盘等块设备使用的高速缓冲区部分, ...

最新文章

  1. 九章量子计算机 科学杂志,张礼立 : 中国 “九章”量子计算机到底厉害在哪?...
  2. 英特尔虚拟化技术发展蓝图
  3. getprivateprofilestring读不到数据_从零到千万用户,我是如何一步步优化MySQL数据库的?...
  4. volatile类型的数据
  5. android资源包混淆,Android---andresguard资源混淆
  6. Eclipse里如何指定目标JRE版本
  7. 80×60长40米的地笼_石家庄Q345矩形方管 220*80*8方管 华东地区
  8. 单片机c语言必背代码_最适合单片机编程的高级语言,除了C语言,别无选择!...
  9. 跨浏览器确定一个窗口的大小
  10. Android的Intent系统调用
  11. mysql yacc 解析_yacc介绍
  12. matlab非线性规划
  13. c语言指针实现字符串拼接
  14. 计算机计算的应用,计算器计算
  15. 微信气泡主题设置_微信要怎么设置气泡?华为手机怎样改微信的气泡和主题方法介绍...
  16. 科学减重才能事半功倍
  17. 在条形码上如何添加日期
  18. 【CodeForces - 1647D】Madoka and the Best School in Russia(分类讨论,因数分解)
  19. CentOS 7 安装配置 k8s 1.25.3
  20. python map函数的作用_python语言基础之map函数,urlib.request,多线程

热门文章

  1. C/C++ 函数出入口
  2. Idea一键导入所有缺省的包
  3. matplotlib绘制多子图共享鼠标光标
  4. 最常用的开源游戏引擎
  5. mac 安装qemu的方法
  6. 毕业找前端开发工作被拒没经验怎么办?
  7. 卸载完mathtype后,word加载项中还是有mathtype的解决方法
  8. (2019春)软件构造:雨课堂试卷(一)
  9. vue导入导出excel组件封装
  10. Java编程:将小写字母转换为大写字母