前面总结了非连续内存区域的内核描述,接着看看他的分配和释放。

一、非连续内存区的分配

不管是vmalloc()还是vmalloc_32()等系列的分配函数最后都会调用__vmalloc_node()函数实现,直接看这个函数的实现。

*__vmalloc_node - allocate virtually contiguous memory

*@size:allocation size

*@align:desired alignment

*@gfp_mask:flags for the page level allocator

*@prot:protection mask for the allocated pages

*@node:node to use for allocation or -1

*@caller:caller's return address

*

*Allocate enough pages to cover @size from the page level

*allocator with @gfp_mask flags. Map them into contiguous

*kernel virtual space, using a pagetable protection of @prot.

*/

static void *__vmalloc_node(unsigned long size, unsigned long align,

gfp_t gfp_mask, pgprot_t prot,

int node, void *caller)

{

struct vm_struct *area;

void *addr;

unsigned long real_size = size;

size = PAGE_ALIGN(size);

if (!size || (size >> PAGE_SHIFT) > totalram_pages)

return NULL;

/*分配相关的结构并对其初始化,在前面介绍过了*/

area = __get_vm_area_node(size, align, VM_ALLOC, VMALLOC_START,

VMALLOC_END, node, gfp_mask, caller);

if (!area)

return NULL;

/*分配物理空间,建立页表映射*/

addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller);

/*

* A ref_count = 3 is needed because the vm_struct and vmap_area

* structures allocated in the __get_vm_area_node() function contain

* references to the virtual address of the vmalloc'ed block.

*/

/*调试用*/

kmemleak_alloc(addr, real_size, 3, gfp_mask);

return addr;

}

struct page **pages;

unsigned int nr_pages, array_size, i;

/*需要减去一个页面,因为在分配结构的时候指定了多一个页面*/

nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;

/*页面指针所占空间大小*/

array_size = (nr_pages * sizeof(struct page *));

area->nr_pages = nr_pages;

/* Please note that the recursion is strictly bounded. */

if (array_size > PAGE_SIZE) {/*如果页面指针空间大于一个页面时,这个空间用非连续内存分配*/

pages = __vmalloc_node(array_size, 1, gfp_mask | __GFP_ZERO,

PAGE_KERNEL, node, caller);

area->flags |= VM_VPAGES;

} else {/*如果页面指针空间所占大小小于一个页面时,用slab机制分配这个空间*/

pages = kmalloc_node(array_size,

(gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO,

node);

}

/*初始化area结构*/

area->pages = pages;

area->caller = caller;

if (!area->pages) {

remove_vm_area(area->addr);

kfree(area);

return NULL;

}

/*对每个页面调用分配函数分配物理空间,

也就是每次分配一个页面*/

for (i = 0; i < area->nr_pages; i++) {

struct page *page;

if (node < 0)/*分配物理页面空间*/

page = alloc_page(gfp_mask);

else

page = alloc_pages_node(node, gfp_mask, 0);

if (unlikely(!page)) {

/* Successfully allocated i pages, free them in __vunmap() */

area->nr_pages = i;

goto fail;

}

area->pages[i] = page;/*初始化area中page数组*/

}

/*因为非连续区间没有建立页表机制,在这里需要建立他*/

if (map_vm_area(area, prot, &pages))

goto fail;

return area->addr;/*返回线性地址*/

fail:

vfree(area->addr);

return NULL;

}

其中map_vm_area()建立页表映射机制的实现就是依次对pgd、pud、pmd、pte的设置。

二、非连续内存区的释放

调用vfree()函数实现

/**

*vfree - release memory allocated by vmalloc()

*@addr:memory base address

*

*Free the virtually continuous memory area starting at @addr, as

*obtained from vmalloc(), vmalloc_32() or __vmalloc(). If @addr is

*NULL, no operation is performed.

*

*Must not be called in interrupt context.

*/

void vfree(const void *addr)

{

BUG_ON(in_interrupt());

/*调试用*/

kmemleak_free(addr);

/*释放工作*/

__vunmap(addr, 1);

}

static void __vunmap(const void *addr, int deallocate_pages)

{

struct vm_struct *area;

if (!addr)

return;

if ((PAGE_SIZE-1) & (unsigned long)addr) {

WARN(1, KERN_ERR "Trying to vfree() bad address (%p)\n", addr);

return;

}

/*从vlist链表和红黑树中移除指定地址的线性区间*/

area = remove_vm_area(addr);

if (unlikely(!area)) {

WARN(1, KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n",

addr);

return;

}

debug_check_no_locks_freed(addr, area->size);

debug_check_no_obj_freed(addr, area->size);

if (deallocate_pages) {

int i;

for (i = 0; i < area->nr_pages; i++) {/*每次释放一个页面*/

struct page *page = area->pages[i];

BUG_ON(!page);

__free_page(page);

}

if (area->flags & VM_VPAGES)/*在创建非连续区间时,如果页面

指针所占的空间大于一个页面时,从非连续内存区间

中分配。所以这里也就从相应的释放*/

vfree(area->pages);

else

kfree(area->pages);/*从slab中释放*/

}

kfree(area);/*释放area*/

return;

}

/**

*remove_vm_area - find and remove a continuous kernel virtual area

*@addr:base address

*

*Search for the kernel VM area starting at @addr, and remove it.

*This function returns the found VM area, but using it is NOT safe

*on SMP machines, except for its size or flags.

*/

struct vm_struct *remove_vm_area(const void *addr)

{

struct vmap_area *va;

/*从红黑树种查找而不是链表,为了效率起见*/

va = find_vmap_area((unsigned long)addr);

if (va && va->flags & VM_VM_AREA) {

struct vm_struct *vm = va->private;

struct vm_struct *tmp, **p;

/*

* remove from list and disallow access to this vm_struct

* before unmap. (address range confliction is maintained by

* vmap.)

*/

write_lock(&vmlist_lock);

/*从链表中找到,然后删除*/

for (p = &vmlist; (tmp = *p) != vm; p = &tmp->next)

;

*p = tmp->next;

write_unlock(&vmlist_lock);

/*调试用*/

vmap_debug_free_range(va->va_start, va->va_end);

/*从红黑树中删除*/

free_unmap_vmap_area(va);

vm->size -= PAGE_SIZE;

return vm;

}

return NULL;

}

总结:linux高端内存非连续区的整体描述以及其分配和释放基本就总结完了。总结的只是一个大概的原理框架,不过根据这个框架对细节的了解应该不难。另外,其中涉及到伙伴系统、slab机制等部分需要再做分析和总结。

linux非连续内存,linux高端内存管理之非连续内存区(分配和释放)相关推荐

  1. 【Linux】Linux的内核空间(低端内存、高端内存)

    内核也是程序,也应该具有自己的虚存空间,但是作为一种为用户程序服务的程序,内核空间有它自己的特点. 内核空间与用户空间的关系 在一个32位系统中,一个程序的虚拟空间最大可以是4GB,那么最直接的做法就 ...

  2. showdialog 尝试读取或写入受保护的内存_轻松一键上4000MHz,XPG龙耀D50 重装RGB内存值不值得高端用户选购?...

    随着今年intel.AMD.nvidia分别推出旗下的高端硬件产品迭代提升,处理器和显卡性能也迎来了新的飞跃,对不少游戏玩家等高端用户来说,有了强劲的硬件,还需要高频内存才能补齐短板,让整机性能再上一 ...

  3. win7计算机内存占用高,win7开机占用内存过高怎么回事?win7开机占用内存过高的处理方法...

    一位用户反馈说win7系统开机加载时间非常长,占用内存无比之高,4G内存被吃掉了80%.电脑内存被占用从而影响我们的电脑运行速度,占用内存越多相对就会变得越慢.针对此问题,小编来和大家详解一下解决方法 ...

  4. 计算机开机内存占用80%,Win10开机后内存占用高80%以上怎么办_win10电脑开机内存占用高达80%以上如何解决...

    近日有不少win10系统用户遇到这样一个现象,就是电脑开机之后,内存占用很费,达到了80%以上了,导致电脑非常卡,许多用户不知道遇到这样的该怎么办,为了解决这样的问题,接下来将给大家讲述一下win10 ...

  5. antimalware service executable占用内存过高_Win10系统svchost.exe进程占用内存和网速过高的解决方法...

    我们在使用Windows10系统的过程中,不少用户一旦发现电脑异常,例如异常卡顿,就会查看一下任务管理器,是否有进程过高占用了CPU.内存.网络等,而在任务管理器中发现了一个名称为"svch ...

  6. 服务器内存使用率高找不到是哪个进程,内存占用率高,但是找不到内存消耗大的程序...

    您好, window 8 对系统软硬件这块的要求相比之前的操作系统而言,可能会高,需要能够支持这块的软硬件或软硬件厂商的支持.我们也了解了下遇到该问题的其他用户,在window 8 开机后可能会有CP ...

  7. LM358(非轨道轨)高端电流采样 廉价充电指示方案

    分析 : LM358选择普通国产方案, 几分钱一个,整体充电板五毛钱. 由于LM358是非轨道轨的, 在输入前先分压为原先的一半,若是轨对轨的运放,可以不用电阻做分压. 然后两个结果进入LM358放大 ...

  8. Linux内存管理之高端内存映射

    一:引子 我们在前面分析过,在linux内存管理中,内核使用3G->4G的地址空间,总共1G的大小.而且有一部份用来做非连续空间的物理映射(vmalloc).除掉这部份空间之外,只留下896M大 ...

  9. Linux内存管理:内存描述之高端内存

    <Linux内存管理:内存描述之内存节点node> <Linux内存管理:内存描述之内存区域zone> <Linux内存管理:内存描述之内存页面page> < ...

  10. 详谈Linux系统《高端内存和低端内存》

    高端内存是Linux中一个重要的概念,初涉Linux时曾经对这个概念非常迷惑.实际上这个概念比较简单,理解这个概念,需要追溯一下Linux的内存管理. 从前,CPU的地址总线只有32位.32的地址总线 ...

最新文章

  1. MySQL数据库中文模糊检索问题
  2. 如何选专业选课题?姚期智院士:首先成为一名科学家
  3. ++i 和 i++ 效率分析(C++)
  4. hive 添加UDF(user define function) hive的insert语句
  5. Python的第三方库pyppeteer
  6. 目标检测——Anchor-Based算法的学习笔记
  7. 工具记录,使用jarsigner 对APK进行签名
  8. 在 Java 应用程序中定时执行任务
  9. word转pdf公式乱码_求助:Word转pdf时公式会公式变成乱码
  10. Eventlog Analyzer日志管理系统、日志分析工具、日志服务器的功能及作用
  11. 想要畅听全网音乐?试试 Listen1吧!
  12. 使用apt更新和升级系统软件
  13. 压力传感器如何直接连接电脑笔记本采集数据表格导出
  14. 改进灰色预测matlab代码,灰色预测模型Matlab代码[比赛已经用过,保真好使]
  15. 深入浅出TensorFlow2函数——tf.data.Dataset.padded_batch
  16. 中学生读以奋斗者为本有感3500字
  17. ML之PDP:机器学习可解释性之部分依赖图(Partial Dependence Plots)之每个特征如何影响您的预测?
  18. Ethernet(以太网) 物理介质(10Base、100Base-T、100Base-TX等)
  19. 数据库是啥?数据库的概念
  20. 暴风影音2018届校园招聘技术类笔试题目

热门文章

  1. python移动文件但不覆盖_怎么做到Python file重复写入之前的内容不被后写入的覆盖...
  2. BZOJ1864: [Zjoi2006]三色二叉树
  3. 《炬丰科技-半导体工艺》SC-1颗粒去除和piranha后漂洗的机理研究
  4. 为什么要推销自己_推销自己:为什么? 如何!
  5. 人人都在推销(销售永不为“奴”)
  6. vscode 中 php 代码格式化插件和其他设置
  7. Docker进阶实战
  8. 运用EXCEL RAND RANK INDEX函数制作抽奖器
  9. mysql实验报告4_实验四∶数据库安全性实验报告.doc
  10. uni-app第三方插件 根据银行卡卡号查询银行类型和卡类型