转自:http://blog.csdn.net/myarrow/article/details/7208777

1. 内存分配函数

相关代码如下:

#define alloc_pages(gfp_mask, order)   alloc_pages_node(numa_node_id(), gfp_mask, order)
#define alloc_page_vma(gfp_mask, vma, addr) alloc_pages(gfp_mask, 0)
#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)

#define __get_free_page(gfp_mask)   __get_free_pages((gfp_mask),0)
#define __get_dma_pages(gfp_mask, order)   __get_free_pages((gfp_mask) | GFP_DMA,(order))

#define pfn_to_page(pfn) (mem_map + ((pfn) - PHYS_PFN_OFFSET))
#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PHYS_PFN_OFFSET)
#define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr))

#define phys_to_page(phys) (pfn_to_page(phys >> PAGE_SHIFT))
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)

#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)

1)__get_free_pages实现代码如下,它返回页的虚拟地址:

  1. unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
  2. {
  3. struct page *page;
  4. /*
  5. * __get_free_pages() returns a 32-bit address, which cannot represent
  6. * a highmem page
  7. */
  8. VM_BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0);
  9. page = alloc_pages(gfp_mask, order);
  10. if (!page)
  11. return 0;
  12. return (unsigned long) page_address(page);
  13. }
  1. /**
  2. * page_address - get the mapped virtual address of a page
  3. * @page: &struct page to get the virtual address of
  4. *
  5. * Returns the page's virtual address.
  6. */
  7. void *page_address(struct page *page)
  8. {
  9. unsigned long flags;
  10. void *ret;
  11. struct page_address_slot *pas;
  12. if (!PageHighMem(page))
  13. return lowmem_page_address(page);
  14. pas = page_slot(page);
  15. ret = NULL;
  16. spin_lock_irqsave(&pas->lock, flags);
  17. if (!list_empty(&pas->lh)) {
  18. struct page_address_map *pam;
  19. list_for_each_entry(pam, &pas->lh, list) {
  20. if (pam->page == page) {
  21. ret = pam->virtual;
  22. goto done;
  23. }
  24. }
  25. }
  26. done:
  27. spin_unlock_irqrestore(&pas->lock, flags);
  28. return ret;
  29. }
  1. static __always_inline void *lowmem_page_address(struct page *page)
  2. {
  3. return __va(PFN_PHYS(page_to_pfn(page)));
  4. }

2)alloc_pages_node

  1. static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
  2. unsigned int order)
  3. {
  4. /* Unknown node is current node */
  5. if (nid < 0)
  6. nid = numa_node_id();
  7. return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));
  8. }

参数nid是要分配内存的 NUMA节点 ID,
参数gfp_mask是 GFP_分配标志,
参数order是分配内存的大小(2^order个页面).
返回值是一个指向第一个(可能返回多个页)page结构的指针,失败时返回NULL。

  1. static inline struct page *
  2. __alloc_pages(gfp_t gfp_mask, unsigned int order,
  3. struct zonelist *zonelist)
  4. {
  5. return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);
  6. }
  1. /*
  2. * This is the 'heart' of the zoned buddy allocator.
  3. */
  4. struct page *
  5. __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
  6. struct zonelist *zonelist, nodemask_t *nodemask)
  7. {
  8. enum zone_type high_zoneidx = gfp_zone(gfp_mask);
  9. struct zone *preferred_zone;
  10. struct page *page;
  11. int migratetype = allocflags_to_migratetype(gfp_mask);
  12. gfp_mask &= gfp_allowed_mask;
  13. lockdep_trace_alloc(gfp_mask);
  14. might_sleep_if(gfp_mask & __GFP_WAIT);
  15. if (should_fail_alloc_page(gfp_mask, order))
  16. return NULL;
  17. /*
  18. * Check the zones suitable for the gfp_mask contain at least one
  19. * valid zone. It's possible to have an empty zonelist as a result
  20. * of GFP_THISNODE and a memoryless node
  21. */
  22. if (unlikely(!zonelist->_zonerefs->zone))
  23. return NULL;
  24. get_mems_allowed();
  25. /* The preferred zone is used for statistics later */
  26. first_zones_zonelist(zonelist, high_zoneidx,
  27. nodemask ? : &cpuset_current_mems_allowed,
  28. &preferred_zone);
  29. if (!preferred_zone) {
  30. put_mems_allowed();
  31. return NULL;
  32. }
  33. /* First allocation attempt */
  34. page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,
  35. zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET,
  36. preferred_zone, migratetype);
  37. if (unlikely(!page))
  38. page = __alloc_pages_slowpath(gfp_mask, order,
  39. zonelist, high_zoneidx, nodemask,
  40. preferred_zone, migratetype);
  41. put_mems_allowed();
  42. trace_mm_page_alloc(page, order, gfp_mask, migratetype);
  43. return page;
  44. }

其接下来的主要调用流程如下:

get_page_from_freelist->

buffered_rmqueue

3) buffered_rmqueue

从区域zone中获取一块大小为2^order的物理内存块,返回该内存块的首个页框的描述符page。

  1. static inline
  2. struct page *buffered_rmqueue(struct zone *preferred_zone,
  3. struct zone *zone, int order, gfp_t gfp_flags,
  4. int migratetype)
  5. {
  6. unsigned long flags;
  7. struct page *page;
  8. int cold = !!(gfp_flags & __GFP_COLD);
  9. again:
  10. if (likely(order == 0)) { //获取一页物理内存(2^0),从当前cpu的高速缓存内存中申请
  11. struct per_cpu_pages *pcp;
  12. struct list_head *list;
  13. local_irq_save(flags);
  14. pcp = &this_cpu_ptr(zone->pageset)->pcp; //获取zone的当前处理器的高速缓存内存描述结构指针
  15. list = &pcp->lists[migratetype];
  16. if (list_empty(list)) { //高速缓存内存为空
  17. pcp->count += rmqueue_bulk(zone, 0,//调用此函数从伙伴系统中分配batch空闲内存到高速缓存内存中
  18. pcp->batch, list,
  19. migratetype, cold);
  20. if (unlikely(list_empty(list)))
  21. goto failed;
  22. }
  23. //我们从pcp->list链表开始的第一个lru起,去寻找相应的struct page结构体
  24. if (cold)
  25. page = list_entry(list->prev, struct page, lru);
  26. else
  27. page = list_entry(list->next, struct page, lru);
  28. //由于被分配出去了,所以高速缓存内存中不再包含这页内存,所以从链表里删除这一项。
  29. list_del(&page->lru);
  30. pcp->count--;  //相应的当前页数也要减少
  31. } else { //获取一块物理内存(2^order)
  32. if (unlikely(gfp_flags & __GFP_NOFAIL)) {
  33. /*
  34. * __GFP_NOFAIL is not to be used in new code.
  35. *
  36. * All __GFP_NOFAIL callers should be fixed so that they
  37. * properly detect and handle allocation failures.
  38. *
  39. * We most definitely don't want callers attempting to
  40. * allocate greater than order-1 page units with
  41. * __GFP_NOFAIL.
  42. */
  43. WARN_ON_ONCE(order > 1);
  44. }
  45. spin_lock_irqsave(&zone->lock, flags);
  46. page = __rmqueue(zone, order, migratetype); //调用函数申请内存
  47. spin_unlock(&zone->lock);
  48. if (!page)
  49. goto failed;
  50. __mod_zone_page_state(zone, NR_FREE_PAGES, -(1 << order));
  51. }
  52. __count_zone_vm_events(PGALLOC, zone, 1 << order);
  53. zone_statistics(preferred_zone, zone, gfp_flags);
  54. local_irq_restore(flags);
  55. VM_BUG_ON(bad_range(zone, page));
  56. if (prep_new_page(page, order, gfp_flags))
  57. goto again;
  58. return page; //返回申请到的内存空间的首页内存页的struct page结构指针
  59. failed:
  60. local_irq_restore(flags);
  61. return NULL;
  62. }

4) rmqueue_bulk

用于多次(count)内存申请.

  1. /*
  2. * Obtain a specified number of elements from the buddy allocator, all under
  3. * a single hold of the lock, for efficiency.  Add them to the supplied list.
  4. * Returns the number of new pages which were placed at *list.
  5. */
  6. static int rmqueue_bulk(struct zone *zone, unsigned int order,
  7. unsigned long count, struct list_head *list,
  8. int migratetype, int cold)
  9. {
  10. int i;
  11. spin_lock(&zone->lock);
  12. for (i = 0; i < count; ++i) {
  13. struct page *page = __rmqueue(zone, order, migratetype);
  14. if (unlikely(page == NULL))
  15. break;
  16. /*
  17. * Split buddy pages returned by expand() are received here
  18. * in physical page order. The page is added to the callers and
  19. * list and the list head then moves forward. From the callers
  20. * perspective, the linked list is ordered by page number in
  21. * some conditions. This is useful for IO devices that can
  22. * merge IO requests if the physical pages are ordered
  23. * properly.
  24. */
  25. if (likely(cold == 0))
  26. list_add(&page->lru, list);
  27. else
  28. list_add_tail(&page->lru, list);
  29. set_page_private(page, migratetype);
  30. list = &page->lru;
  31. }
  32. __mod_zone_page_state(zone, NR_FREE_PAGES, -(i << order));
  33. spin_unlock(&zone->lock);
  34. return i;
  35. }

5) __rmqueue

用于一次内存申请。

  1. /*
  2. * Do the hard work of removing an element from the buddy allocator.
  3. * Call me with the zone->lock already held.
  4. */
  5. static struct page *__rmqueue(struct zone *zone, unsigned int order,
  6. int migratetype)
  7. {
  8. struct page *page;
  9. retry_reserve:
  10. page = __rmqueue_smallest(zone, order, migratetype);
  11. if (unlikely(!page) && migratetype != MIGRATE_RESERVE) {
  12. page = __rmqueue_fallback(zone, order, migratetype);
  13. /*
  14. * Use MIGRATE_RESERVE rather than fail an allocation. goto
  15. * is used because __rmqueue_smallest is an inline function
  16. * and we want just one call site
  17. */
  18. if (!page) {
  19. migratetype = MIGRATE_RESERVE;
  20. goto retry_reserve;
  21. }
  22. }
  23. trace_mm_page_alloc_zone_locked(page, order, migratetype);
  24. return page;
  25. }

2. 内存释放函数

相关宏定义如下:

    1. #define __free_page(page) __free_pages((page), 0)
    2. #define free_page(addr) free_pages((addr),0)

Kernel 3.0.8 内存管理函数【转】的更多相关文章

  1. linux kernel学习笔记-5内存管理_转

    void * kmalloc(size_t size, gfp_t gfp_mask); kmalloc()第一个参数是要分配的块的大小,第一个参数为分配标志,用于控制kmalloc()的行为. km ...

  2. 内存管理运算符new delete与内存管理函数malloc free的区别——已经他们对对象创建的过程。

    (1)内存管理函数与内存管理运算符的区别 内存管理函数有内存分配函数,malloc calloc realloc 以及内存释放函数free. 内存管理运算符有new 和delete. 两种内存管理方式 ...

  3. C++内存管理-重载内存管理函数

    记录学习的点点滴滴,参考侯捷<<C++内存管理>> 我们先重载一下C++的几个内存管理函数 operator new, operator new[], operator del ...

  4. Linux C 堆内存管理函数malloc()、calloc()、realloc()、free()详解

    C 编程中,经常需要操作的内存可分为下面几个类别: 堆栈区(stack):由编译器自动分配与释放,存放函数的参数值,局部变量,临时变量等等,它们获取的方式都是由编译器自动执行的 堆区(heap):一般 ...

  5. 内存管理内幕mallco及free函数实现

    原文:https://www.ibm.com/developerworks/cn/linux/l-memory/ 为什么必须管理内存 内存管理是计算机编程最为基本的领域之一.在很多脚本语言中,您不必担 ...

  6. 结合源码看nginx-1.4.0之nginx内存管理详解

    目录 0. 摘要 1. nginx内存结构设计 2. nginx内存数据结构 3. nginx内存管理原理 4. 一个简单的内存模型 5. 小结 6. 参考资料 0. 摘要 内存管理,是指软件运行时对 ...

  7. Linux 0.11源码阅读笔记-内存管理

    内存管理 Linux内核使用段页式内存管理方式. 内存池 物理页:物理空闲内存被划分为固定大小(4k)的页 内存池:所有空闲物理页组成内存池,以页为单位进行分配回收.并通过位图记录了每个物理页是否空闲 ...

  8. C 语言函数手册:涵盖字符测试、字符串操作、内存管理、时间换算、数学计算、文件操作、进程管理、文件权限控制、信号处理、接口处理、环境变量、终端控制

    1. 字符测试函数 函数 说明 isascii() 判断字符是否为ASCII码字符 2. 字符串操作 函数 说明 gcvt() 将浮点型数转换为字符串(四舍五入) index() 查找字符串并返回首次 ...

  9. <转载>内存管理内幕-动态分配的选择、折衷和实现 对malloc内存分配有个简单的描述,对内存管理有个大致的说明

    这篇文章看后感觉不错,和我在glibc下的hurdmalloc.c文件里关于malloc的实现基本意思相同,同时,这篇文章还介绍了一些内存管理方面的知识,值得推荐. 原文链接地址为:http://ww ...

随机推荐

  1. linux一次性解压多个.gz或者.tar.gz文件

    对于解压多个.gz文件的,用此命令: for gz in *.gz; do gunzip $gz; done 对于解压多个.tar.gz文件的,用下面命令: for tar in *.tar.gz; ...

  2. cf786E ALT (最小割+倍增优化建图)

    如果把“我全都要”看作是我全不要的话,就可以用最小割解决啦 源点S,汇点T 我们试图让每个市民作为一个等待被割断的路径 把狗狗给市民:建边(S,i,1),其中i是市民 把狗狗给守卫:建边(j,T,1) ...

  3. 【洛谷P3586】LOG

    题目大意:维护一个集合,支持单点修改.查询小于 X 的数的个数.查询小于 X 的数的和. 题解:学习到了动态开点线段树.对于一棵未经离散化的权值线段树来说,对于静态开点来说,过大的值域会导致不能承受的 ...

  4. 【洛谷P1854】花店橱窗 线性dp+路径输出

    题目大意:给定 N 个数字,编号分别从 1 - N,M 个位置,N 个数字按照相对大小顺序放在 M 个位置里,每个数放在每个位置上有一个对答案的贡献值,求一种摆放方式使得贡献值最大. 题解:一道典型的 ...

  5. XML:特殊字符转换

    <     < 小于号 >     > 大于号 &    & 和 &apos;   ' 单引号 "   " 双引号 实体必须以符号& ...

  6. elasticsearch-head安装及启动

    head是用于监控Elasticsearch状态的客户端插件,包括数据可视化,增删改查工具,es语句的可视化等等. 5.0之后的安装方式如下: git clone git://github.com/m ...

  7. 函数和常用模块【day04】:函数的非固定参数(三)

    本节内容 1.概述 2.默认参数 3.参数组 4.总结 一.概述 在上一篇博客中我已经写了,位置参数和关键字参数,下面我们来谈谈默认参数和参数组 二.默认参数 默认参数指的是,我们在传参之前,先给参数 ...

  8. 启动eclipse弹出提示Version 1.7.0_79 of the JVM is not suitable for this product. Version: 1.8 or greater is required怎样解决

    启动eclipse时弹出如下弹出框: 解决办法: 在eclipse安装目录下找到eclipse.ini文件,并在 -vmargs-Dosgi.requiredJavaVersion=1.8 前面加上 ...

  9. 标准遗传算法(实数编码 python实现)模拟二进制交叉SBX 多项式变异

    代码地址: https://github.com/guojun007/real_sga 本部分是采用实数编码的标准遗传算法,整体流程与上一篇二进制编码的基本一致, 主要区别在于本部分的交叉操作为模拟二 ...

  10. for、foreach和Iterator区别及ConcurrentModificationException异常

    (问:1.for.foreach和Iterator遍历有什么区别    2.遍历删除ConcurrentModificationException异常.) 1.在形式上 for的形式是 for(int ...