先上基础,下图是Linux的内存映射模型

  • 每一个进程都有自己的进程空间,进程空间的0-3G是用户空间,3G-4G是内核空间
  • 每个进程的用户空间不在同一个物理内存页,但是所有的进程的内核空间对应同样的物理地址
  • vmalloc分配的地址可以高端内存,也可以是低端内存
  • 0-896MB的物理地址是线性映射到物理映射区的。

内存动态申请

和应用层一样,内核程序也需要动态的分配内存,不同的是,内核进程可以控制分配的内存是在用户空间还是内核空间,前者可以用于给用户空间的堆区分配内存,eg,用户进程的用户空间的malloc最终就会通过系统调用回调内核空间的内存分配函数,此时该内存分配函数就属于该用户进程,可以给在该用户进程的堆区分配空间并返回,最终使得一个用会进程在自己的用户空间获得内存分配;后者只在内核空间分配,所以用户进程不能直接访问该空间,所以多用在满足内核程序自身的内存需求,下面是Linux内核空间申请内存常用API:

kmalloc - kfree

kmalloc申请的内存在物理内存上是连续的,他们与真实的物理地址只有一个固定的偏移,因此存在简单的转换关系。这个API 多用来申请不到一个page大小的内存。kmalloc的底层需要调用__get_free_pages,参数中表示内存类型的gtp_t flags正是这个函数的缩写,常用的内存类型有GFP_USER,GFP_KERNEL,GFP_ATOMIC几种。

  • GFP_USER表示为用户空间页分配内存,可以阻塞;
  • GFP_KERNEL是最常用的flag,注意,使用这个flag来申请内存时,如果暂时不能满足,会引起进程阻塞,So,一定不要在中断处理函数,tasklet和内核定时器等非进程上下文中使用GFP_KERNEL!!!
  • GFP_ATOMIC就可以用于上述三种情境,这个flag表示如果申请的内存不能用,则立即返回。
  1. /**
  2. * kmalloc - allocate memory
  3. * @size: how many bytes of memory are required.
  4. * @flags: the type of memory to allocate.
  5. * The @flags argument may be one of:
  6. * %GFP_USER - Allocate memory on behalf of user.  May sleep.
  7. * %GFP_KERNEL - Allocate normal kernel ram.  May sleep.
  8. * %GFP_ATOMIC - Allocation will not sleep.  May use emergency pools.
  9. *
  10. * For example, use this inside interrupt handlers.
  11. */
  12. void *kmalloc(size_t size, gfp_t flags);
  13. /**
  14. * kfree - free previously allocated memory
  15. * @objp: pointer returned by kmalloc.
  16. * If @objp is NULL, no operation is performed.
  17. */
  18. void kfree(const void *objp);

同系列API还有

  1. void *kzalloc(size_t size, gfp_t flags)

__get_free_pages - free_pages

__get_free_pages()与kmalloc()一样是物理连续的内存,这一系列函数是Linux内核中最底层的用于获取空闲内存的方法,因为底层的buddy算法都是以(2^n)×PAGE_SIZE来管理内存的,所以他们总是以页为单位分配内存的

  1. unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)  void free_pages(unsigned long addr, unsigned int order)

同系列API还有

  1. unsigned long __get_free_page(gfp_t gfp)        unsigned long get_zeroed_page(gfp_t gfp_mask)    struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
  1. void free_page(unsigned long addr)

vmalloc - vfree

vmalloc在虚拟内存空间给出一块连续的内存区,实质上,这片连续的虚拟内存在物理内存中并不一定连续,所以vmalloc申请的虚拟内存和物理内存之间也就没有简单的换算关系,正因如此,vmalloc()通常用于分配远大于__get_free_pages()的内存空间,它的实现需要建立新的页表,此外还会调用使用GFP_KERN的kmalloc,so,一定不要在中断处理函数,tasklet和内核定时器等非进程上下文中使用vmalloc!

  1. /**
  2. * vmalloc  -  allocate virtually contiguous memory
  3. * @size:          allocation size
  4. * Allocate enough pages to cover @size from the page level allocator and map them into contiguous kernel virtual space.
  5. */void *vmalloc(unsigned long size)   /**
  6. *      vfree  -  release memory allocated by vmalloc()
  7. *      @addr:          memory base address
  8. */void vfree(const void *addr)

同系列的API还有

  1. /**
  2. * vmalloc_32  -  allocate virtually contiguous memory (32bit addressable)
  3. * @size:          allocation size
  4. * Allocate enough 32bit PA addressable pages to cover @size from the page level allocator and map them into contiguous kernel virtual space.
  5. */void *vmalloc_32(unsigned long size)

slab缓存

我们知道,页是内存映射的基本单位,但内核中很多频繁创建的对象所需内存都不到一页,此时如果仍然按照页映射的方式,频繁的进行分配和释放就会造成资源的浪费,同时也会降低系统性能。为了解决的这样的问题,内核引入了slab机制,使对象在前后两次被使用时被分配在同一块内存或同一类内存空间,且保留了基本的数据结构,就可以大大提高效率。kmalloc的底层即是使用slab算法管理分配的内存的。注意,slab依然是以页为单位进行映射,只是映射之后分割这些页为相同的更小的单元,从而节省了内存。slab分配的单元不能小于32B或大于128K。

  1. /**
  2. * kmem_cache_create - 创建slab缓存对象
  3. * @name:slab缓存区名字,
  4. * @size:slab分配的缓存区的每一个单元的大小
  5. * @align:缓存区内存的对齐方式,一般给0
  6. * @flags:控制分配的位掩码,
  7. * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5) to catch references to uninitialised memory.
  8. * %SLAB_RED_ZONE - Insert `Red' zones around the allocated memory to check for buffer overruns.
  9. * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware cacheline.  This can be beneficial if you're counting cycles as closely as davem.
  10. * %SLAB_CACHE_DMA - Use GFP_DMA memory
  11. * %SLAB_STORE_USER - Store the last owner for bug hunting
  12. *define SLAB_PANIC - Panic if kmem_cache_create() fails
  13. */struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,unsigned long flags, void (*ctor)(void *))/**
  14. * kmem_cache_alloc - Allocate an object from this cache.
  15. * @cachep: The cache to allocate from.
  16. * @flags: See kmalloc().
  17. * The flags are only relevant if the cache has no available objects.
  18. */void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)  /**
  19. * kmem_cache_free - Deallocate an object
  20. * @cachep: The cache the allocation was from.
  21. * @objp: The previously allocated object.
  22. * Free an object which was previously allocated from this cache.
  23. */void kmem_cache_free(struct kmem_cache *cachep, void *objp)  void kmem_cache_destroy(struct kmem_cache *s)

范例

  1. //创建slab对象
  2. struct kmem_cache_t *xj_sbcache;
  3. xj_sbcache = kmem_cache_create("xjslab",sizeof(struct xj_unit_t),0,SLAB_CACHE_DMA|SLAB_PANIC,NULL,NULL);//分配slab缓存
  4. struct xj_unit_t *xj_unit;
  5. xj_unit = kmem_cache_alloc(xj_sbcache,GFP_KERNEL);
  6. /* 使用slab缓存 */
  7. /* 释放slab缓存 */
  8. kmem_cache_free(xj_sbcache, xj_unit);
  9. /* 销毁slab缓存 */
  10. kmem_cache_destroy(xj_sbcache);

内存池

除了slab机制,内核还提供了传统的内存池机制来管理小块内存的分配。内存池主要是用来解决可能出现的内存不足的情况,因为一个内存池在创建的时候就已经分配好了一内存,当我们用mempool_alloc向一个已经创建好的内存池申请申请内存时,该函数首先会尝试回调内存池创建时的分配内存函数,如果已经没有内存可以分配,他就会使用内存池创建时预先分配的内存,这样就可以避免因为无内存分配而陷入休眠,当然,如果预分配的内存也已经使用完毕,还是会陷入休眠。slab机制的目的是提高内存使用率以及内存管理效率,内存池的目的是避免内存的分配失败。下面是内核中提供的关于内存池的API

  1. /**
  2. * mempool_create - create a memory pool
  3. * @min_nr:    the minimum number of elements guaranteed to be  allocated for this pool.
  4. * @alloc_fn:  user-defined element-allocation function.
  5. * @free_fn:   user-defined element-freeing function.
  6. * @pool_data: optional private data available to the user-defined functions.
  7. *
  8. * this function creates and allocates a guaranteed size, preallocated memory pool. The pool can be used from the mempool_alloc() and mempool_free() functions.
  9. * This function might sleep. Both the alloc_fn() and the free_fn() functions might sleep - as long as the mempool_alloc() function is not called from IRQ contexts.
  10. */
  11. mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, mempool_free_t *free_fn, void *pool_data)
  12. /**
  13. * mempool_alloc - allocate an element from a specific memory pool
  14. * @pool:pointer to the memory pool which was allocated via mempool_create().
  15. * @gfp_mask:  the usual allocation bitmask.
  16. * this function only sleeps if the alloc_fn() function sleeps or returns NULL. Note that due to preallocation, this function never* fails when called from process contexts. (it might fail if called from an IRQ context.)
  17. */
  18. void * mempool_alloc(mempool_t *pool, gfp_t gfp_mask)
  19. /**
  20. * mempool_free - return an element to the pool.
  21. * @element:   pool element pointer.
  22. * @pool:pointer to the memory pool which was allocated via mempool_create().
  23. *
  24. * this function only sleeps if the free_fn() function sleeps.
  25. */
  26. void mempool_free(void *element, mempool_t *pool)
  27. /**
  28. * mempool_destroy - deallocate a memory pool
  29. * @pool:pointer to the memory pool which was allocated via mempool_create().
  30. *
  31. * Free all reserved elements in @pool and @pool itself.  This function only sleeps if the free_fn() function sleeps.
  32. */
  33. void mempool_destroy(mempool_t *pool)
本文作者:佚名
来源:51CTO

Linux驱动技术(一) _内存申请相关推荐

  1. 详解Linux驱动技术(五) _设备阻塞/非阻塞读写

    在Linux驱动程序编写过程中,设备阻塞/非阻塞读写是一种非常重要的技术.它可以实现高效的数据传输和事件处理,提高系统的性能和响应速度.在本文中,我们将深入探讨Linux驱动技术(五) _设备阻塞/非 ...

  2. linux malloc free 内存碎片_内存申请malloc/new与内存释放free/delete的区别

    前面的文章小编说过,存放在堆上的数据是由程序员小哥哥负责申请和回收的.今天我们就说一下动态申请内存的指令以及他们之间的区别.最普遍的申请内存方式就是malloc/free与new/delete; 为了 ...

  3. Linux驱动技术(八) _并发控制技术

    为了实现对临界资源的有效管理,应用层的程序有原子变量,条件变量,信号量来控制并发,同样的问题也存在与驱动开发中,比如一个驱动同时被多个应用层程序调用,此时驱动中的全局变量会同时属于多个应用层进程的进程 ...

  4. Linux驱动技术(四) _异步通知技术

    异步通知的全称是"信号驱动的异步IO",通过"信号"的方式,放期望获取的资源可用时,驱动会主动通知指定的应用程序,和应用层的"信号"相对应, ...

  5. Linux驱动技术(六) _内核中断

    在硬件上,中断源可以通过中断控制器向CPU提交中断,进而引发中断处理程序的执行,不过这种硬件中断体系每一种CPU都不一样,而Linux作为操作系统,需要同时支持这些中断体系,如此一来,Linux中就提 ...

  6. Linux驱动技术(三) _DMA编程

    DMA即Direct Memory Access,是一种允许外设直接存取内存数据而没有CPU参与的技术,当外设对于该块内存的读写完成之后,DMAC通过中断通知CPU,这种技术多用于对数据量和数据传输速 ...

  7. linux驱动访问内存,linux驱动笔记八(内存与IO访问)

    X86处理器中存在I/O空间的概念,I/O空间是相对于内存空间而言的,通过特定的指令in, out 来访问. 目前,大多数嵌入式微控制器如ARM, POWERPC等并不提供I/O空间,而仅存在内存空间 ...

  8. 《Linux驱动:DMA直接内存访问》

    目录 一.前言 二.DMA传输主体 三.S3c2440上的DMA 3.1 DMA请求源 3.2 DMA状态机 3.3 DMA请求模式 3.4 DMA服务模式 3.5 DMA传输模式 3.6 DMA读写 ...

  9. 关注:截至2008年Linux相关技术被中国企业申请专利情况汇总

    获取Linux操作系统信息的方法 申请号/专利号: 02129337 一种获取Linux操作系统信息的方法,通过Linux操作系统的proc文件系统,读取Linux内核中各模块的信息:对读出的信息进行 ...

最新文章

  1. Android第十五课 Jni自带的iconv库不支持GBK转码
  2. python基础知识理解
  3. 主流WAF架构分析与探索
  4. 三维数组地址计算_科学计算NumPy
  5. Emerged strategy 涌现战略
  6. curl请求本地域名问题
  7. VBOX+WINDOWSSERVER208R2实现虚拟机内FTP服务器搭建
  8. javascript移动设备触屏事件
  9. 解决 could not initialize proxy [com.xxx.xxx.xxx.entity.xxxInfo#1] - no Session
  10. mysql数据库性能监控工具MONyog实战
  11. 类似win7系统泡泡屏保
  12. vue-video-player 断点续播
  13. 【C语言】动态内存管理(heap)
  14. C++/Qt 计算24点
  15. python拼多多推广多店爬虫
  16. 51单片机undefined identifier问题求助
  17. Java通过substring截取指定字符
  18. ply文件格式详细说明
  19. matlab 2016a
  20. decoration

热门文章

  1. 新来了个技术总监:谁再用 @Async 创建线程以后就不用来了!!
  2. 面了一个 32 岁的程序员,一看就是“卷”出来的
  3. 一个牛逼的 多级缓存 实现方案!
  4. 如何提升微服务的幸福感
  5. Thread.sleep(0) 有什么用?
  6. 浅谈 CAP 和 Paxos 共识算法
  7. 数据挖掘竞赛指南:曾经的数据挖掘少年,如今的阿里算法大佬
  8. 茅台App首发就登顶!单日下载量43万,甚至还没开始试运行
  9. 用简单术语让你看到贝叶斯优化之美
  10. YOLOv4 中的 Mish 激活函数