Kernel 3.0.8 内存管理函数【转】
转自: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实现代码如下,它返回页的虚拟地址:
- unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order)
- {
- struct page *page;
- /*
- * __get_free_pages() returns a 32-bit address, which cannot represent
- * a highmem page
- */
- VM_BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0);
- page = alloc_pages(gfp_mask, order);
- if (!page)
- return 0;
- return (unsigned long) page_address(page);
- }
- /**
- * page_address - get the mapped virtual address of a page
- * @page: &struct page to get the virtual address of
- *
- * Returns the page's virtual address.
- */
- void *page_address(struct page *page)
- {
- unsigned long flags;
- void *ret;
- struct page_address_slot *pas;
- if (!PageHighMem(page))
- return lowmem_page_address(page);
- pas = page_slot(page);
- ret = NULL;
- spin_lock_irqsave(&pas->lock, flags);
- if (!list_empty(&pas->lh)) {
- struct page_address_map *pam;
- list_for_each_entry(pam, &pas->lh, list) {
- if (pam->page == page) {
- ret = pam->virtual;
- goto done;
- }
- }
- }
- done:
- spin_unlock_irqrestore(&pas->lock, flags);
- return ret;
- }
- static __always_inline void *lowmem_page_address(struct page *page)
- {
- return __va(PFN_PHYS(page_to_pfn(page)));
- }
2)alloc_pages_node
- static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
- unsigned int order)
- {
- /* Unknown node is current node */
- if (nid < 0)
- nid = numa_node_id();
- return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));
- }
参数nid是要分配内存的 NUMA节点 ID,
参数gfp_mask是 GFP_分配标志,
参数order是分配内存的大小(2^order个页面).
返回值是一个指向第一个(可能返回多个页)page结构的指针,失败时返回NULL。
- static inline struct page *
- __alloc_pages(gfp_t gfp_mask, unsigned int order,
- struct zonelist *zonelist)
- {
- return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);
- }
- /*
- * This is the 'heart' of the zoned buddy allocator.
- */
- struct page *
- __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
- struct zonelist *zonelist, nodemask_t *nodemask)
- {
- enum zone_type high_zoneidx = gfp_zone(gfp_mask);
- struct zone *preferred_zone;
- struct page *page;
- int migratetype = allocflags_to_migratetype(gfp_mask);
- gfp_mask &= gfp_allowed_mask;
- lockdep_trace_alloc(gfp_mask);
- might_sleep_if(gfp_mask & __GFP_WAIT);
- if (should_fail_alloc_page(gfp_mask, order))
- return NULL;
- /*
- * Check the zones suitable for the gfp_mask contain at least one
- * valid zone. It's possible to have an empty zonelist as a result
- * of GFP_THISNODE and a memoryless node
- */
- if (unlikely(!zonelist->_zonerefs->zone))
- return NULL;
- get_mems_allowed();
- /* The preferred zone is used for statistics later */
- first_zones_zonelist(zonelist, high_zoneidx,
- nodemask ? : &cpuset_current_mems_allowed,
- &preferred_zone);
- if (!preferred_zone) {
- put_mems_allowed();
- return NULL;
- }
- /* First allocation attempt */
- page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,
- zonelist, high_zoneidx, ALLOC_WMARK_LOW|ALLOC_CPUSET,
- preferred_zone, migratetype);
- if (unlikely(!page))
- page = __alloc_pages_slowpath(gfp_mask, order,
- zonelist, high_zoneidx, nodemask,
- preferred_zone, migratetype);
- put_mems_allowed();
- trace_mm_page_alloc(page, order, gfp_mask, migratetype);
- return page;
- }
其接下来的主要调用流程如下:
get_page_from_freelist->
buffered_rmqueue
3) buffered_rmqueue
从区域zone中获取一块大小为2^order的物理内存块,返回该内存块的首个页框的描述符page。
- static inline
- struct page *buffered_rmqueue(struct zone *preferred_zone,
- struct zone *zone, int order, gfp_t gfp_flags,
- int migratetype)
- {
- unsigned long flags;
- struct page *page;
- int cold = !!(gfp_flags & __GFP_COLD);
- again:
- if (likely(order == 0)) { //获取一页物理内存(2^0),从当前cpu的高速缓存内存中申请
- struct per_cpu_pages *pcp;
- struct list_head *list;
- local_irq_save(flags);
- pcp = &this_cpu_ptr(zone->pageset)->pcp; //获取zone的当前处理器的高速缓存内存描述结构指针
- list = &pcp->lists[migratetype];
- if (list_empty(list)) { //高速缓存内存为空
- pcp->count += rmqueue_bulk(zone, 0,//调用此函数从伙伴系统中分配batch空闲内存到高速缓存内存中
- pcp->batch, list,
- migratetype, cold);
- if (unlikely(list_empty(list)))
- goto failed;
- }
- //我们从pcp->list链表开始的第一个lru起,去寻找相应的struct page结构体
- if (cold)
- page = list_entry(list->prev, struct page, lru);
- else
- page = list_entry(list->next, struct page, lru);
- //由于被分配出去了,所以高速缓存内存中不再包含这页内存,所以从链表里删除这一项。
- list_del(&page->lru);
- pcp->count--; //相应的当前页数也要减少
- } else { //获取一块物理内存(2^order)
- if (unlikely(gfp_flags & __GFP_NOFAIL)) {
- /*
- * __GFP_NOFAIL is not to be used in new code.
- *
- * All __GFP_NOFAIL callers should be fixed so that they
- * properly detect and handle allocation failures.
- *
- * We most definitely don't want callers attempting to
- * allocate greater than order-1 page units with
- * __GFP_NOFAIL.
- */
- WARN_ON_ONCE(order > 1);
- }
- spin_lock_irqsave(&zone->lock, flags);
- page = __rmqueue(zone, order, migratetype); //调用函数申请内存
- spin_unlock(&zone->lock);
- if (!page)
- goto failed;
- __mod_zone_page_state(zone, NR_FREE_PAGES, -(1 << order));
- }
- __count_zone_vm_events(PGALLOC, zone, 1 << order);
- zone_statistics(preferred_zone, zone, gfp_flags);
- local_irq_restore(flags);
- VM_BUG_ON(bad_range(zone, page));
- if (prep_new_page(page, order, gfp_flags))
- goto again;
- return page; //返回申请到的内存空间的首页内存页的struct page结构指针
- failed:
- local_irq_restore(flags);
- return NULL;
- }
4) rmqueue_bulk
用于多次(count)内存申请.
- /*
- * Obtain a specified number of elements from the buddy allocator, all under
- * a single hold of the lock, for efficiency. Add them to the supplied list.
- * Returns the number of new pages which were placed at *list.
- */
- static int rmqueue_bulk(struct zone *zone, unsigned int order,
- unsigned long count, struct list_head *list,
- int migratetype, int cold)
- {
- int i;
- spin_lock(&zone->lock);
- for (i = 0; i < count; ++i) {
- struct page *page = __rmqueue(zone, order, migratetype);
- if (unlikely(page == NULL))
- break;
- /*
- * Split buddy pages returned by expand() are received here
- * in physical page order. The page is added to the callers and
- * list and the list head then moves forward. From the callers
- * perspective, the linked list is ordered by page number in
- * some conditions. This is useful for IO devices that can
- * merge IO requests if the physical pages are ordered
- * properly.
- */
- if (likely(cold == 0))
- list_add(&page->lru, list);
- else
- list_add_tail(&page->lru, list);
- set_page_private(page, migratetype);
- list = &page->lru;
- }
- __mod_zone_page_state(zone, NR_FREE_PAGES, -(i << order));
- spin_unlock(&zone->lock);
- return i;
- }
5) __rmqueue
用于一次内存申请。
- /*
- * Do the hard work of removing an element from the buddy allocator.
- * Call me with the zone->lock already held.
- */
- static struct page *__rmqueue(struct zone *zone, unsigned int order,
- int migratetype)
- {
- struct page *page;
- retry_reserve:
- page = __rmqueue_smallest(zone, order, migratetype);
- if (unlikely(!page) && migratetype != MIGRATE_RESERVE) {
- page = __rmqueue_fallback(zone, order, migratetype);
- /*
- * Use MIGRATE_RESERVE rather than fail an allocation. goto
- * is used because __rmqueue_smallest is an inline function
- * and we want just one call site
- */
- if (!page) {
- migratetype = MIGRATE_RESERVE;
- goto retry_reserve;
- }
- }
- trace_mm_page_alloc_zone_locked(page, order, migratetype);
- return page;
- }
2. 内存释放函数
相关宏定义如下:
- #define __free_page(page) __free_pages((page), 0)
- #define free_page(addr) free_pages((addr),0)
Kernel 3.0.8 内存管理函数【转】的更多相关文章
- linux kernel学习笔记-5内存管理_转
void * kmalloc(size_t size, gfp_t gfp_mask); kmalloc()第一个参数是要分配的块的大小,第一个参数为分配标志,用于控制kmalloc()的行为. km ...
- 内存管理运算符new delete与内存管理函数malloc free的区别——已经他们对对象创建的过程。
(1)内存管理函数与内存管理运算符的区别 内存管理函数有内存分配函数,malloc calloc realloc 以及内存释放函数free. 内存管理运算符有new 和delete. 两种内存管理方式 ...
- C++内存管理-重载内存管理函数
记录学习的点点滴滴,参考侯捷<<C++内存管理>> 我们先重载一下C++的几个内存管理函数 operator new, operator new[], operator del ...
- Linux C 堆内存管理函数malloc()、calloc()、realloc()、free()详解
C 编程中,经常需要操作的内存可分为下面几个类别: 堆栈区(stack):由编译器自动分配与释放,存放函数的参数值,局部变量,临时变量等等,它们获取的方式都是由编译器自动执行的 堆区(heap):一般 ...
- 内存管理内幕mallco及free函数实现
原文:https://www.ibm.com/developerworks/cn/linux/l-memory/ 为什么必须管理内存 内存管理是计算机编程最为基本的领域之一.在很多脚本语言中,您不必担 ...
- 结合源码看nginx-1.4.0之nginx内存管理详解
目录 0. 摘要 1. nginx内存结构设计 2. nginx内存数据结构 3. nginx内存管理原理 4. 一个简单的内存模型 5. 小结 6. 参考资料 0. 摘要 内存管理,是指软件运行时对 ...
- Linux 0.11源码阅读笔记-内存管理
内存管理 Linux内核使用段页式内存管理方式. 内存池 物理页:物理空闲内存被划分为固定大小(4k)的页 内存池:所有空闲物理页组成内存池,以页为单位进行分配回收.并通过位图记录了每个物理页是否空闲 ...
- C 语言函数手册:涵盖字符测试、字符串操作、内存管理、时间换算、数学计算、文件操作、进程管理、文件权限控制、信号处理、接口处理、环境变量、终端控制
1. 字符测试函数 函数 说明 isascii() 判断字符是否为ASCII码字符 2. 字符串操作 函数 说明 gcvt() 将浮点型数转换为字符串(四舍五入) index() 查找字符串并返回首次 ...
- <转载>内存管理内幕-动态分配的选择、折衷和实现 对malloc内存分配有个简单的描述,对内存管理有个大致的说明
这篇文章看后感觉不错,和我在glibc下的hurdmalloc.c文件里关于malloc的实现基本意思相同,同时,这篇文章还介绍了一些内存管理方面的知识,值得推荐. 原文链接地址为:http://ww ...
随机推荐
- Android DownloadManager 的使用
分类: android 技巧2013-05-28 10:32 3278人阅读 评论(1) 收藏 举报 目录(?)[+] 从Android 2.3(API level 9)开始Android用系 ...
- Linux中配置Aria2 RPC Server
启动Aria2 RPC Server 直接在终端中执行aria2c --enable-rpc --rpc-allow-origin-all可直接开启RPC服务. 这种方法并不能进行个性化的参数设置,需 ...
- A1029. Median
Given an increasing sequence S of N integers, the median is the number at the middle position. For e ...
- A1086. Tree Traversals Again
An inorder binary tree traversal can be implemented in a non-recursive way with a stack. For example ...
- 【POJ3694】Network
题目大意:给定一个 N 个点,M 条边的无向图,支持 Q 次操作,每次可以向该无向图中加入一条边,并需要回答当前无向图中桥的个数. 题解:(暴力:Q 次 Tarjan) 先进行一次 Tarjan 求出 ...
- (转)Maven pom.xml 配置详解
背景:maven一直感觉既熟悉又陌生,归根结底还是自己不太熟. 1 什么是pom? pom作为项目对象模型.通过xml表示maven项目,使用pom.xml来实现.主要描述了项目:包括配置文件:开发者 ...
- 使用 <!DOCTYPE html> 让 <div><img></div>中的图片下面产生几个像素的空白间隔
今天算是第一次使用 <!DOCTYPE html> 不经意间发现图片下方有5个像素左右的空白间隔,检查半天也没查出原因. 最后百度了一下,网上说这是 <!DOCTYPE html&g ...
- springboot集成druid连接池
使用druid连接池主要有几步: 1.添加jar和依赖 <groupId>org.mybatis.spring.boot</groupId> <artifactId> ...
- Python基础【day01】:初始模块(五)
本节内容 1.标准库 1.sys 2.os 2.第三方库 1.for mac 2.for linux Python的强大之处在于他有非常丰富和强大的标准库和第三方库,几乎你想实现的任何功能都有相应的P ...
- .net MVC使用NPOI读取Excel模板,再写入数据
NPOI其实已经介绍的差不多了,再贴一个方便以后复制粘贴. 亮点其实是 Server.MapPath 这个东西,可以找到MVC工程下的文件夹,找路径还是很方便的. /// <summary> ...