转自: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. Division, UVa 72(暴力求解)

    题目链接:https://vjudge.net/problem/UVA-725 Write a program that finds and displays all pairs of 5-digit ...

  2. 使用debootstrap制作debian-jessie系统docker镜像

    先看一下Docker官网提示:In general, you'll want to start with a working machine that is running the distribut ...

  3. time_t和difftime

    在C++中,下面这段代码可以获取一段时间差. time_t t1 = time(NULL); Sleep(); time_t t2 = time(NULL); cout << diffti ...

  4. MySQL的1067错误解决方法

    今天在学校的时候MySQL还运行的好好的,关机来公司后MySQL一直报错,错误为1067,网上找了好多办法,但是大都没效果,因此对这个错误做个总结: 打开你的安装目录下,查看my.ini文件中MySQ ...

  5. word公式的使用

    插入->公式->插入新公式 优点:可以表示一些特殊符号,而且word公式的字更好看. 方法: 1.Shift+Enter,公式转入下一行 2.选择内嵌或显示 3.选择性粘贴->粘贴成 ...

  6. NOIP 普及组 2014 螺旋矩阵

    传送门 https://www.cnblogs.com/violet-acmer/p/9898636.html 题解: 这道题挺有意思的,有点考思维吧. 大体思路是用四个pair<int ,in ...

  7. 洛谷 P1880 [NOI1995] 石子合并(区间DP)

    传送门 https://www.cnblogs.com/violet-acmer/p/9852294.html 题解: 这道题是石子合并问题稍微升级版 这道题和经典石子合并问题的不同在于,经典的石子合 ...

  8. vs2013配置opencv2.4.13

    此方法配置简单,方便易行,解压opencv2.4.13后得到opencv文件夹,进行如下步骤: 1.添加环境变量 用户变量,新建,变量名opencv,值D:\opencv\build 系统变量,Pat ...

  9. HSRP vs VRRP

    HSRP:(Hot Standby Router Protocol)-热备份路由协议 是cisco平台一种特有的技术,是cisco的私有协议. VRRP:(Virtual Router Redunda ...

  10. ElasticSearch入门介绍一

    ElasticSearch 关于es的几个概念: 集群:多个运行es节点可以组成一个集群,它们拥有相同的cluster.name. 节点:运行es的实例 索引:相当于数据库database,一个集群可 ...