本章主要介绍Linux内核的内存管理。

  • kmalloc函数的内幕

    • 不正确所获取的内存空间清零
    • 分配的区域在物理内存中也是连续的
    • flags參数
      • <linux/slab.h>
      • <linux/gfp.h>
        • GFP_KERNEL

          • 在空暇内存较少时把当前进程转入休眠以等待一个页面
          • 分配内存的函数必须是可重入的
        • GFP_ATOMIC
          • 用于在中断处理例程或其它执行于进程上下文之外的代码中分配内存,不会休眠
        • GFP_USER
          • 用于为用户空间页分配内存。可能会休眠
        • GFP_HIGHUSER
          • 类似于GFP_USER,只是假设有高端内存的话就从那里分配
        • GFP_NOIO, GFP_NOFS
          • 这两个标志的功能类似于GFP_KERNEL,可是为内核分配内存的工作方式加入了一些限制。具有GFP_NOFS标志的分配不同意运行不论什么文件系统调用。而GFP_NOIO禁止不论什么I/O的初始化。

            这两个标志主要在文件系统和虚拟内存代码中使用,这些代码中的内存分配可休眠。但不应该发生递归的文件系统调用

        • __GFP_DMA
          • 该标志请求分配发生在可进行DMA的内存区段中
        • __GFP_HIGHHEM
          • 这个标志表明要分配的内存可位于高端内存
        • __GFP_COLD
          • 这个标志请求尚未使用的“冷”页面,对于DMA读取的页面分配。可使用这个标志
        • __GFP_NOWARN
          • 非常少使用。能够避免内核在无法满足分配请求时产生警告
        • __GFP_HIGH
          • 标记了一个高优先级的请求,它同意为紧急善而消耗由内核保留的最后一些页面
        • __GFP_REPEAT, __GFP_NOFAIL, __GFP_NORETRY
          • 告诉分配器在满足分配请求而遇到困难时应该採取何种行为
          • __GFP_REPEAT表示“努力再尝试一次”,它会又一次尝试分配。但仍有可能失效
          • __GFP_NOFAIL标志告诉分配器始终不返回失败。它会努力满足分配请求,不鼓舞使用这个标志
          • __GFP_NORETRY告诉分配器,假设所请求的内存不可获得,就马上返回
    • 内存区段
      • __GFP_DMA和__GFP_HIGHHEM的使用与平台相关
      • Linux内核把内存分为三个区段:可用于DMA的内存、常规内存以及高端内存
      • 可用于DMA的内存指存在于特别地址范围内的内存,外设能够利用这些内存运行DMA訪问
      • 高端内存是32位平台为了訪问大量的内存而存在的一种机制
      • 假设没有指定特定的标志。则kmalloc会在常规区段和DMA区段搜索
      • 假设设置了__GFP_HIGHHEM标志。则全部三个区段都会被搜索
      • 内存区段的背后机制在mm/page_alloc.c中实现
    • size參数
      • Linux处理内存分配的方法是。创建一系列的内存对象池,每一个池中的内存块大小是固定一致的。

        处理分配请求时,就直接在包括有足够大的内存块的池中传递一个整块给请求者

      • kmalloc能处理的最小的内存块是32或者64
      • 假设希望代码具有完整的可移植性。则不应该分配大于128KB的内存
  • 后备快速缓存

    • Linux内核的调整缓存管理有时称为“slab分配器”
    • slag分配器实现的快速缓存具有kmem_cache_t类型
    • kmem_cache_t *kem_cache_create(const char *name, size_t size, size_t offset, unsigned long flags, void (*constructor) (void *, keme_cache_t *, unsigned long flags), void (*destructor) (void *, kmem_cache_t *, unsigned long flags));
    • 參数flags控制怎样完毕分配
      • SLAB_NO_REAP

        • 能够保护快速缓存在系统寻找内存的时候不会被降低
      • SLAB_HWCACHE_ALIGN
        • 要求全部数据对象跟调整缓存行(cache line)对齐。实际的操作则依赖于主要平台的硬件调整缓存布局
      • SLAB_CACHE_DMA
        • 要求每一个数据对象都从可用于DMA的内存区段中分配
    • mm/slab.c
    • 能够使用同一个函数同一时候作为constructor和destructor使用,当调用的是一个constructor函数的时候,slab分配器总是传递SLAB_CTOR_CONSTRUCTOR标志
    • void *kmem_cache_alloc(kmem_cache_t *cache, int flags);
    • void kmem_cache_free(kmem_cache_t *cache, const void *obj);
    • int kmem_cache_destroy(kmem_cache_t *cache);
    • 快速缓存的使用统计情况能够从/proc/slabinfo获得
    • 内存池
      • 内存池事实上就是某种形式的后备快速缓存,它试图始终保存空暇的内存,以便把在紧急状态下使用
      • 内存池对象的类型为mempool_t
      • <linux/mempool.h>
        • mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, mempool_free_t *free_fn, void *pool_data);
        • typedef void *(mempool_alloc_t) (int gfp_mask, void *pool_data);
        • typedef void (mempool_free_t) (void *element, void *pool_data);
        • void *mempool_alloc(mempool_t *pool, int gfp_mask);
        • void mempool_free(void *element, mempool_t *pool);
        • int mempool_resize(mempool_t *pool, int new_min_nr, int gfp_mask);
        • void mempool_destroy(mempool_t *pool);
      • example
        • cache = kmem_cache_create(…);
        • pool =- mempool_create(MY_POOL_MINIMUM, mempool_alloc_slab, mempool_free_slab, cache);
      • mempool会分配一些内存块,空暇且不会真正得到使用
      • 应尽量避免在驱动程序代码中使用mempool
  • get_free_page和相关函数
    • get_zeroed_page(unsigned int flags);

      • 返回指向新页面的指针并将页面清零
    • __get_free_page(unsigned int flags);
      • 类似于get_zeroed_page,但不清零页面
    • __get_free_pages(unsigned int flags, unsigned int order);
      • 分配若干(物理连续的)页面,并返回指向该内在区域第一个字节的指针。但不清零页面
      • 參数order是要申请或释放的页面数的以2为底的对数
    • void free_page(unsigned long addr);
    • void free_pages(unsigned long addr, unsigned long order);
    • alloc_pages接口
      • struct page *alloc_pages_node(int nid, unsigned int flags, unsigned int order);

        • nid是NUMA节点的ID号
      • struct page *alloc_page(unsigned int flags, unsigned int order);
      • struct page *alloc_page(unsigned int flags);
      • void __free_page(struct page *page);
      • void __free_pages(struct page *page, unsigned int order);
      • void free_hot_page(struct page *page);
      • void free_code_page(struct page *page);
    • Subtopic 7
  • vmalloc及其辅助函数
    • 分配虚拟地址空间的连续区域,这段区域右物理上可能是不连续的,内核却觉得它们在地址上是连续的
    • vmalloc获得的内存使用起来效率不高
    • <linux/vmalloc.h>
      • void *vmalloc(unsigned long size);
      • void vfree(void *addr);
      • void *ioremap(unsigned long offset, unsigned long size);
      • void iounmap(void *addr);
    • vmalloc能够获得的地址在VMALLOC_START到VMALLOC_END的范围中。这两个符号都在<asm/pgtable.h>中定义
    • 使用vmalloc函数的正确场合是在分配一大块连续的、仅仅在软件中存在的、用于缓冲的内存区域的时候
    • ioremap很多其它用于映射(物理的)PCI缓冲区地址到(虚拟的)内核空间
  • per-CPU变量
    • 当建立一个per-CPU变量时。系统中的每一个处理器都会拥有该变量的特有副本
    • 不须要锁定
    • 能够保存在相应处理器的快速缓存中
    • <linux/percpu.h>
      • DEFINE_PER_CPU(type, name);
      • get_cpu_var(variable);
      • put_cpu_var(variable);
      • per_cpu(variable, int cpu_id);
      • void *alloc_percpu(type);
      • void *__alloc_percpu(size_t size, size_t align);
      • per_cpu_ptr(void *per_cpu_var, int cpu_id);
      • EXPORT_PER_CPU_SYMBOL(per_cpu_var);
      • EXPORT_PER_CPU_SYMBOL_GPL(per_cpu_var);
      • DECLARE_PER_CPU(type, name);
  • 获取大的缓冲区
    • 在引导时获得专用缓冲区

      • <linux/bootmem.h>

        • void *alloc_bootmem(unsigned long size);
        • void *alloc_bootmem_low(unsigned long size);
        • void *alloc_bootmem_pages(unsigned long size);
        • void *alloc_bootmem_low_pages(unsigned long size);
        • void free_bootmem(unsigned long addr, unsigned long size);
      • 这些函数要么分配整个页,要么分配不在页面边界上对齐的内存区
      • 除非使用具有_low后缀的版本号,否则分配的内存可能会是高端内存

《Linux Device Drivers》第八章 分配内存——note的更多相关文章

  1. 《Linux Device Drivers》第十章 中断处理——note

    概述:系统要及时的感知硬件的状态,通常有两种方式:一种是轮询.一种是通过响应硬件中断.前者会浪费处理器的时间,而后者不会. 准备并口 在没有节设定产生中断之前,并口是不会产生中断的 并口的标准规定设置 ...

  2. 《Linux Device Drivers》第十五章 内存映射和DMA——note

    简单介绍 很多类型的驱动程序编程都须要了解一些虚拟内存子系统怎样工作的知识 当遇到更为复杂.性能要求更为苛刻的子系统时,本章所讨论的内容迟早都要用到 本章的内容分成三个部分 讲述mmap系统调用的实现 ...

  3. 《Linux Device Drivers》第十四章 Linux 设备型号

    基本介绍 2.6内核设备模型来提供的抽象叙述性描述的一般系统的结构,为了支持各种不同的任务 电源管理和系统关机 用户空间与通信 热插拔设备 设备类型 kobject.kset和子系统 kobject是 ...

  4. Linux设备驱动程序学习之分配内存

    内核为设备驱动提供了一个统一的内存管理接口,所以模块无需涉及分段和分页等问题. 我已经在第一个scull模块中使用了 kmalloc 和 kfree 来分配和释放内存空间. kmalloc 函数内幕 ...

  5. linux device drivers ch02

    ch02.构造和运行模块 模块的构造: #include <linux/init.h> #include <linux/module.h> MODULE_LICENSE(&qu ...

  6. 当linux报 “-bash: fork: 无法分配内存”

    “-bash: fork: 无法分配内存”,发现连了好多终端,然后断开了一个终端,然后这边终端可以敲命令了 [root@172.16.31.105 /home/www/test]# free -m  ...

  7. 《Linux Device Drivers》第十八章 TTY驱动程序——note

    简单介绍 tty设备的名称是从过去的电传打字机缩写而来,最初是指连接到Unix系统上的物理或虚拟终端 Linux tty驱动程序的核心紧挨在标准字符设备驱动层之下,并提供了一系列的功能,作为接口被终端 ...

  8. 《Linux Device Drivers》第十二章 PCI司机——note

    一个简短的引论 它给这一章总线架构的高级概述 集中访问讨论Peripheral Component Interconnect(PCI,外围组件互连)外设内核函数 PCI公交车是最好的支持的内核总线 本 ...

  9. 《Linux Device Drivers》 第十七章 网络驱动程序——note

    基本介绍 第三类是标准的网络接口Linux设备,本章介绍的内核,其余的交互网络接口描述 网络接口,必须使用特定的内核数据结构本身注册,与外部分组交换数据线打电话时准备 经常使用的文件上的网络接口操作是 ...

随机推荐

  1. [ Luogu 3935 ] Calculating

    \(\\\) \(Description\) 若\(x\)分解质因数结果为\(x=p_1^{k_1}p_2^{k_2}\cdots p_n^{k_n}\),令\(f(x)=(k_1+1)(k_2+1) ...

  2. CF869C The Intriguing Obsession

    思路: 分别在两种不同颜色的岛屿群之间进行搭桥.因为相同颜色的岛屿之间不能有边,任意两个相同颜色的岛屿不能同时和另外一个不同颜色的岛屿都有边.实现: #include <bits/stdc++. ...

  3. Android常见问题总结(二)

    1.布局文件LinearLayout线性布局添加内容报错. 解决方法: 线性布局LinearLayout中包裹的元素多余1个需要添加android:orientation属性. 2.android 的 ...

  4. Hibernate框架之HQL查询与Criteria 查询的区别

    Hibernate框架提供了HQL查询和Criteria 查询.下面对这两种查询分别做个例子.也好对这两种查询方法有个大概的了解.就用房屋信息表做例子,查询所有房屋信息. HQL语句查询所有房屋信息: ...

  5. UI设计四要素

    信息.样式.布局.交互. +层次: UI所有的工作都可以从这几个方面入手.

  6. SDK_按键消息的拦截

    按键消息的拦截 拦截是为了在原有功能的基础上增加自己的操作 扩展:当按钮接收到点击消息的时候,响应的是WM_LBUTTONDOWN消息,按钮的会被这个消息打包成一个WM_COMMAND 消息发送给父窗 ...

  7. vba txt读写的几种方式

    四种方式写txt 1.这种写出来的是ANSI格式的txt Dim TextExportFile As String TextExportFile = ThisWorkbook.Path & & ...

  8. os下,vs code 自动编译ts

    nodejs安装ts npm install -g typescript 进入工程目录,用命令初始化ts(生成tsconfig.json) tsc --init 如果要指定生成目录,打开tsconfi ...

  9. Django线上部署教程:腾讯云+Ubuntu+Django+Uwsgi(转载)

    网站名称: 向东的笔记本 本文链接: https://www.eastnotes.com/post/29 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议.转载请注明出处! ...

  10. vue-router + axios token登录状态认证

    vue项目中登录状态判断往往基于jwt认证,我们可以采用判断本地是否存在token,及token是否过期或token值错误 1.利用vue-router 钩子函数判断本地是否存在token impor ...