本文转载自:http://blog.chinaunix.net/uid-26859697-id-5573776.html

kmalloc()是基于slab/slob/slub分配分配算法上实现的,不少地方将其作为slab/slob/slub分配算法的入口,实际上是略有区别的。

现在分析一下其实现:

  1. 【file:/include/linux/slab.h】
  2. /**
  3. * kmalloc - allocate memory
  4. * @size: how many bytes of memory are required.
  5. * @flags: the type of memory to allocate.
  6. *
  7. * kmalloc is the normal method of allocating memory
  8. * for objects smaller than page size in the kernel.
  9. *
  10. * The @flags argument may be one of:
  11. *
  12. * %GFP_USER - Allocate memory on behalf of user. May sleep.
  13. *
  14. * %GFP_KERNEL - Allocate normal kernel ram. May sleep.
  15. *
  16. * %GFP_ATOMIC - Allocation will not sleep. May use emergency pools.
  17. * For example, use this inside interrupt handlers.
  18. *
  19. * %GFP_HIGHUSER - Allocate pages from high memory.
  20. *
  21. * %GFP_NOIO - Do not do any I/O at all while trying to get memory.
  22. *
  23. * %GFP_NOFS - Do not make any fs calls while trying to get memory.
  24. *
  25. * %GFP_NOWAIT - Allocation will not sleep.
  26. *
  27. * %__GFP_THISNODE - Allocate node-local memory only.
  28. *
  29. * %GFP_DMA - Allocation suitable for DMA.
  30. * Should only be used for kmalloc() caches. Otherwise, use a
  31. * slab created with SLAB_DMA.
  32. *
  33. * Also it is possible to set different flags by OR'ing
  34. * in one or more of the following additional @flags:
  35. *
  36. * %__GFP_COLD - Request cache-cold pages instead of
  37. * trying to return cache-warm pages.
  38. *
  39. * %__GFP_HIGH - This allocation has high priority and may use emergency pools.
  40. *
  41. * %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail
  42. * (think twice before using).
  43. *
  44. * %__GFP_NORETRY - If memory is not immediately available,
  45. * then give up at once.
  46. *
  47. * %__GFP_NOWARN - If allocation fails, don't issue any warnings.
  48. *
  49. * %__GFP_REPEAT - If allocation fails initially, try once more before failing.
  50. *
  51. * There are other flags available as well, but these are not intended
  52. * for general use, and so are not documented here. For a full list of
  53. * potential flags, always refer to linux/gfp.h.
  54. */
  55. static __always_inline void *kmalloc(size_t size, gfp_t flags)
  56. {
  57. if (__builtin_constant_p(size)) {
  58. if (size > KMALLOC_MAX_CACHE_SIZE)
  59. return kmalloc_large(size, flags);
  60. #ifndef CONFIG_SLOB
  61. if (!(flags & GFP_DMA)) {
  62. int index = kmalloc_index(size);
  63. if (!index)
  64. return ZERO_SIZE_PTR;
  65. return kmem_cache_alloc_trace(kmalloc_caches[index],
  66. flags, size);
  67. }
  68. #endif
  69. }
  70. return __kmalloc(size, flags);
  71. }

kmalloc()的参数size表示申请的空间大小,而flags则表示分配标志。kamlloc的分配标志众多,各标志都分配标识特定的bit位,藉此可以多样组合。

GFP_USER:用于表示为用户空间分配内存,可能会引起休眠;

GFP_KERNEL:内核内存的常规分配,可能会引起休眠;

GFP_ATOMIC:该分配不会引起休眠,但可能会使用应急内存资源,通常用于中断处理中;

GFP_HIGHUSER:使用高端内存进行分配;

GFP_NOIO:分配内存时,禁止任何IO操作;

GFP_NOFS:分配内存时,禁止任何文件系统操作;

GFP_NOWAIT:分配内存时禁止休眠;

__GFP_THISNODE:分配内存时,仅从本地节点内存中分配;

GFP_DMA:从DMA内存中分配合适的内存,应仅使用于kmalloc的cache分配;

__GFP_COLD:用于请求分配冷热页中的冷页;

__GFP_HIGH:用于表示该分配优先级较高并可能会使用应急内存资源;

__GFP_NOFAIL:用于指示该分配不允许分配失败,该标志需要慎用;

__GFP_NORETRY:如果分配内存未能够直接获取到,则不再尝试分配,直接放弃;

__GFP_NOWARN:如果分配过程中失败,不上报任何告警;

__GFP_REPEAT:如果分配过程中失败,则尝试再次申请;

函数入口if判断内的__builtin_constant_p是Gcc内建函数,用于判断一个值是否为编译时常量,是则返回true,否则返回false。也就意味着如果调用kmalloc()传入常量且该值大于KMALLOC_MAX_CACHE_SIZE(即申请空间超过kmalloc()所能分配最大cache的大小),那么将会通过kmalloc_large()进行分配;否则都将通过__kmalloc()进行分配。如果通过kmalloc_large()进行内存分配,将会经kmalloc_large()->kmalloc_order()->__get_free_pages(),最终通过Buddy伙伴算法申请所需内存。

伙伴算法前面已经分析过了,不再赘述,接下来看__kmalloc()的实现:

  1. 【file:/mm/slub.c】
  2. void *__kmalloc(size_t size, gfp_t flags)
  3. {
  4. struct kmem_cache *s;
  5. void *ret;
  6. if (unlikely(size > KMALLOC_MAX_CACHE_SIZE))
  7. return kmalloc_large(size, flags);
  8. s = kmalloc_slab(size, flags);
  9. if (unlikely(ZERO_OR_NULL_PTR(s)))
  10. return s;
  11. ret = slab_alloc(s, flags, _RET_IP_);
  12. trace_kmalloc(_RET_IP_, ret, size, s->size, flags);
  13. return ret;
  14. }

该函数同样判断申请是否超过最大cache大小,如果是则通过kmalloc_large()进行分配;接着通过申请大小及申请标志调用kmalloc_slab()查找适用的kmem_cache;最后通过slab_alloc()进行slab分配。

具体看一下kmalloc_slab()的实现:

  1. 【file:/mm/slab_commmon.c】
  2. /*
  3. * Find the kmem_cache structure that serves a given size of
  4. * allocation
  5. */
  6. struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags)
  7. {
  8. int index;
  9. if (unlikely(size > KMALLOC_MAX_SIZE)) {
  10. WARN_ON_ONCE(!(flags & __GFP_NOWARN));
  11. return NULL;
  12. }
  13. if (size <= 192) {
  14. if (!size)
  15. return ZERO_SIZE_PTR;
  16. index = size_index[size_index_elem(size)];
  17. } else
  18. index = fls(size - 1);
  19. #ifdef CONFIG_ZONE_DMA
  20. if (unlikely((flags & GFP_DMA)))
  21. return kmalloc_dma_caches[index];
  22. #endif
  23. return kmalloc_caches[index];
  24. }

如果申请的大小超过KMALLOC_MAX_SIZE最大值,则返回NULL表示失败;如果申请大小小于192,且不为0,将通过size_index_elem宏转换为下标后,经size_index全局数组取得索引值,否则将直接通过fls()取得索引值;最后如果开启了DMA内存配置且设置了GFP_DMA标志,将结合索引值通过kmalloc_dma_caches返回kmem_cache管理结构信息,否则将通过kmalloc_caches返回该结构。

由此可以看出kmalloc()实现较为简单,起分配所得的内存不仅是虚拟地址上的连续存储空间,同时也是物理地址上的连续存储空间。这是有别于后面将会分析到的vmalloc()申请所得的内存。

此外再过一下kfree()的接口实现,该函数在多处均有实现,主要是在slab.c/slob.c/slub.c中,所以也说kmalloc()和kfree()是基于slab/slob/slub实现的。这里接前面的slub算法,主要分析一下slub.c中的kfree()实现:

  1. 【file:/mm/slub.c】
  2. void kfree(const void *x)
  3. {
  4. struct page *page;
  5. void *object = (void *)x;
  6. trace_kfree(_RET_IP_, x);
  7. if (unlikely(ZERO_OR_NULL_PTR(x)))
  8. return;
  9. page = virt_to_head_page(x);
  10. if (unlikely(!PageSlab(page))) {
  11. BUG_ON(!PageCompound(page));
  12. kfree_hook(x);
  13. __free_memcg_kmem_pages(page, compound_order(page));
  14. return;
  15. }
  16. slab_free(page->slab_cache, page, object, _RET_IP_);
  17. }

该函数实现简单,首先是经过trace_kfree()记录kfree轨迹,然后if (unlikely(ZERO_OR_NULL_PTR(x)))对地址做非零判断,接着virt_to_head_page(x)将虚拟地址转换到页面;再是判断if (unlikely(!PageSlab(page)))判断该页面是否作为slab分配管理,如果是的话则转为通过slab_free()进行释放,否则将进入if分支中;在if分支中,将会kfree_hook()做释放前kmemleak处理(该函数主要是封装了kmemleak_free()),完了之后将会__free_memcg_kmem_pages()将页面释放,同时该函数内也将cgroup释放处理。

kmalloc()和kfree()也就这么简单了。

Linux-3.14.12内存管理笔记【kmalloc与kfree实现】【转】的更多相关文章

  1. Linux-3.14.12内存管理笔记【伙伴管理算法(1)】

    前面分析了memblock算法.内核页表的建立.内存管理框架的构建,这些都是x86处理的setup_arch()函数里面初始化的,因地制宜,具有明显处理器的特征.而start_kernel()接下来的 ...

  2. Linux-3.14.12内存管理笔记【构建内存管理框架(1)】

    传统的计算机结构中,整个物理内存都是一条线上的,CPU访问整个内存空间所需要的时间都是相同的.这种内存结构被称之为UMA(Uniform Memory Architecture,一致存储结构).但是随 ...

  3. Linux-3.14.12内存管理笔记【伙伴管理算法(2)】

    前面已经分析了linux内存管理算法(伙伴管理算法)的准备工作. 具体的算法初始化则回到start_kernel()函数接着往下走,下一个函数是mm_init(): [file:/init/main. ...

  4. Linux-3.14.12内存管理笔记【构建内存管理框架(5)】

    前面已经分析了内存管理框架的构建实现过程,有部分内容未完全呈现出来,这里主要做个补充. 如下图,这是前面已经看到过的linux物理内存管理框架的层次关系. 现着重分析一下各个管理结构体的成员功能作用. ...

  5. 2. Linux-3.14.12内存管理笔记【系统启动阶段的memblock算法(2)】

    memory:表示可用可分配的内存: 结束完memblock算法初始化前的准备工作,回到memblock算法初始化及其算法实现上面.memblock是一个很简单的算法. memblock算法的实现是, ...

  6. 1. Linux-3.14.12内存管理笔记【系统启动阶段的memblock算法(1)】

    memblock算法是linux内核初始化阶段的一个内存分配器(它取代了原来的bootmem算法),实现较为简单.负责page allocator初始化之前的内存管理和分配请求. 分析memblock ...

  7. Linux-3.14.12内存管理笔记【构建内存管理框架(2)】

    前面构建内存管理框架,已经将内存管理node节点设置完毕,接下来将是管理区和页面管理的构建.此处代码实现主要在于setup_arch()下的一处钩子:x86_init.paging.pagetable ...

  8. Linux-3.14.12内存管理笔记【建立内核页表(1)】

    前面已经分析过了Intel的内存映射和linux的基本使用情况,已知head_32.S仅是建立临时页表,内核还是要建立内核页表,做到全面映射的.下面就基于RAM大于896MB,而小于4GB ,切CON ...

  9. Linux-3.14.12内存管理笔记【内存泄漏检测kmemleak示例】【转】

    本文转载自:http://blog.chinaunix.net/uid-26859697-id-5758037.html 分析完kmemleak实现后,照常实验一下,以确定功能正常. 如kmemche ...

随机推荐

  1. HDU - 1686 Oulipo KMP匹配运用

    id=25191" target="_blank" style="color:blue; text-decoration:none">HDU - ...

  2. 127.0.0.1和localhost和本机IP三者的区别

    1,什么是环回地址??与127.0.0.1的区别呢?? 环回地址是主机用于向自身发送通信的一个特殊地址(也就是一个特殊的目的地址). 可以这么说:同一台主机上的两项服务若使用环回地址而非分配的主机地址 ...

  3. Java设计模式博客全文件夹

    转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/40031567 今天来对这23种设计模式做个总结.咱使用设计模式的目的是为了可重用代码.让代 ...

  4. jquery实现图片的依次加载图片

    css代码: ul#portfolio{margin:0;padding:0;} ul#portfolio li{float:left;margin:0 5px 0 0;width:250px;hei ...

  5. 30:根据排序标识flag给数组排序

    题目描述:输入整型数组和排序标识,对其元素按照升序或降序进行排序 接口说明 原型: void sortIntegerArray(Integer[] pIntegerArray, int iSortFl ...

  6. Linux U盘只读解决方法

    Linux Fat的U盘只读,这个问题经常出现,原因大家都说了是U盘的错误,出现这种情况后,一般的解决方案是 mount | grep <U盘的标签> # 找到你的U盘的对应的设备名称,如 ...

  7. 给定一个递增序列,a1 <a2 <...<an 。定义这个序列的最大间隔为d=max{ai+1 - ai }(1≤i<n),现在要从a2 ,a3 ..an-1 中删除一个元素。问剩余序列的最大间隔最小是多少?

    // ConsoleApplication5.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<vector> ...

  8. HDFS源码分析之LightWeightGSet

    LightWeightGSet是名字节点NameNode在内存中存储全部数据块信息的类BlocksMap需要的一个重要数据结构,它是一个占用较低内存的集合的实现,它使用一个数组array存储元素,使用 ...

  9. Appium python自动化测试系列之使用HTMLTestRunner生成测试报告(十三)

    ​13.1 测试报告概述 13.1.1 测试报告的定义 在前面章节我们已经讲了自动化基础的很多东西,如果说掌握了,而且自己动手去练习了,我相信在一些初级的面试中是没任何问题的,今天我们接触的应该算是一 ...

  10. p2p webrtc服务器搭建系列1: 房间,信令,coturn打洞服务器

    中继(relay) 在RTCPeeConnection中,使用ICE框架来保证RTCPeerConnection能实现NAT穿越 ICE,全名叫交互式连接建立(Interactive Connecti ...