03 2022 档案

摘要:图4-17给出了内核在处理缺页异常时,可能使用的各种代码路径的一个粗略的概观。 arch/x86/kernel/entry_32.S中的一个汇编例程用作缺页异常的入口,但其立即调用了arch/x86/mm/fault_32.c中的C例程do_page_fault。 图4-18给出了该例程的代码流程图 阅读全文
posted @ 2022-03-26 22:13 while(true);; 阅读(564) 评论(0) 推荐(0)
摘要:堆是一个连续的内存区域,在扩展时自下至上增长。的mm_struct结构,包含了堆在虚拟地址空间中的起始和当前结束地址(start_brk和brk)。 <mm_types.h> struct mm_struct { ... unsigned long start_brk, brk, start_sta 阅读全文
posted @ 2022-03-26 21:17 while(true);; 阅读(67) 评论(0) 推荐(0)
摘要:C标准库提供了mmap函数建立映射。在内核一端,提供了两个系统调用mmap和mmap2。两个函数的参数相同。 asmlinkage unsigned long sys_mmap{2}(unsigned long addr, unsigned long len,unsigned long prot, 阅读全文
posted @ 2022-03-26 00:12 while(true);; 阅读(353) 评论(0) 推荐(0)
摘要:内核提供了各种函数来操作进程的虚拟内存区域。在建立或删除映射时,创建和删除区域(以及查找用于新区域的适当的内存位置)是所需要的标准操作。如图4-10所示。 将虚拟地址关联到区域 通过虚拟地址,find_vma可以查找用户地址空间中结束地址在给定地址之后的第一个区域,即满足addr < vm_area 阅读全文
posted @ 2022-03-24 21:44 while(true);; 阅读(110) 评论(0) 推荐(0)
摘要:struct mm_struct提供了进程在内存中布局的所有必要信息。另外,它还包括下列成员,用于管理用户进程在虚拟地址空间中的所有内存区域。(其中管理虚拟地址空间所有内存区域) <mm_types.h> struct mm_struct { struct vm_area_struct * mmap 阅读全文
posted @ 2022-03-24 20:09 while(true);; 阅读(215) 评论(0) 推荐(0)
摘要:由于所有用户进程总的虚拟地址空间比可用的物理内存大得多,因此只有最常用的部分才与物理页帧关联。我们考察一下通过文本编辑器操作文件的情况。通常用户只关注文件结尾处,因此尽管整个文件都映射到内存中,实际上只使用了几页来存储文件末尾的数据。至于文件开始处的数据,内核只需要在地址空间保存相关信息,如数据在磁 阅读全文
posted @ 2022-03-24 18:00 while(true);; 阅读(163) 评论(0) 推荐(0)
摘要:虚拟地址空间中包含了若干区域。其分布方式是特定于体系结构的,但所有方法都有下列共同成分。  当前运行代码的二进制代码。该代码通常称之为text,所处的虚拟内存区域称之为text段。  程序使用的动态库的代码。  存储全局变量和动态产生的数据的堆。  用于保存局部变量和实现函数/过程调用的栈。 阅读全文
posted @ 2022-03-24 17:49 while(true);; 阅读(261) 评论(0) 推荐(0)
摘要:kmalloc的实现 kmalloc的基础是一个数组,其中是一些分别用于不同内存长度的slab缓存。数组项是cache_sizes的实例,该数据结构定义如下: <slab_def.h> struct cache_sizes { size_t cs_size; kmem_cache_t *cs_cac 阅读全文
posted @ 2022-03-23 00:43 while(true);; 阅读(92) 评论(0) 推荐(0)
摘要:如果一个分配的对象已经不再需要,那么必须使用kmem_cache_free返回给slab分配器。图3-52给出了该函数的代码流程图。 类似于分配,根据per-CPU缓存的状态不同,有两种可选的操作流程。如果per-CPU缓存中的对象数目低于允许的限制,则在其中存储一个指向缓存中对象的指针。 mm/s 阅读全文
posted @ 2022-03-23 00:20 while(true);; 阅读(177) 评论(0) 推荐(0)
摘要:kmem_cache_alloc用于从特定的缓存获取对象。类似于所有的malloc函数,其结果可能是指向分配内存区的指针,也可能分配失败,返回NULL指针。该函数需要两个参数:用于获取对象的缓存,以及精确描述分配特征的标志变量。 <slab.h> void *kmem_cache_alloc (km 阅读全文
posted @ 2022-03-22 23:55 while(true);; 阅读(1167) 评论(0) 推荐(0)
摘要:创建新的slab缓存必须调用kmem_cache_create。该函数需要很多参数。 mm/slab.c struct kmem_cache *kmem_cache_create (const char *name, size_t size, size_t align,unsigned long f 阅读全文
posted @ 2022-03-22 21:51 while(true);; 阅读(582) 评论(0) 推荐(0)
摘要:1. 数据结构 每个缓存由kmem_cache结构的一个实例表示,该结构的内容如下 mm/slab.c struct kmem_cache { /* 1) per-CPU数据,在每次分配/释放期间都会访问 */ struct array_cache *array[NR_CPUS]; /* 2) 可调 阅读全文
posted @ 2022-03-22 20:01 while(true);; 阅读(172) 评论(0) 推荐(0)
摘要:基本上,slab缓存由图3-44所示的两部分组成:保存管理性数据的缓存对象和保存被管理对象的各个slab。 每个缓存只负责一种对象类型(例如struct unix_sock实例),或提供一般性的缓冲区。各个缓存中slab的数目各有不同,这与已经使用的页的数目、对象长度和被管理对象的数目有关。 1. 阅读全文
posted @ 2022-03-22 18:53 while(true);; 阅读(807) 评论(0) 推荐(0)
摘要:内核也必须经常分配内存,但无法借助于标准库的函数。上面描述的伙伴系统支持按页分配内存,但这个单位太大了。如果需要为一个10个字符的字符串分配空间,分配一个4 KiB或更多空间的完整页面,不仅浪费而且完全不可接受。 提供小内存块不是slab分配器的唯一任务。由于结构上的特点,它也用作一个缓存,主要针对 阅读全文
posted @ 2022-03-22 18:18 while(true);; 阅读(236) 评论(1) 推荐(0)
摘要:根据上文的讲述,我们知道物理上连续的映射对内核是最好的,但并不总能成功地使用。在分配一大块内存时,可能竭尽全力也无法找到连续的内存块。在用户空间中这不是问题,因为普通进程设计为使用处理器的分页机制,当然这会降低速度并占用TLB。在内核中也可以使用同样的技术。 如图3-37所示,在IA-32系统中,紧 阅读全文
posted @ 2022-03-21 20:32 while(true);; 阅读(317) 评论(0) 推荐(1)
摘要:__free_pages是一个基础函数,用于实现内核API中所有涉及内存释放的函数。其代码流程图如图3-35所示。 __free_pages首先判断所需释放的内存是单页还是较大的内存块?如果释放单页,则不还给伙伴系统,而是置于per-CPU缓存中,对很可能出现在CPU高速缓存的页,则放置到热页的列表 阅读全文
posted @ 2022-03-21 00:20 while(true);; 阅读(320) 评论(0) 推荐(0)
摘要:如果内核找到适当的内存域,具有足够的空闲页可供分配,那么还有两件事情需要完成。首先它必须检查这些页是否是连续的(到目前为止,只知道有许多空闲页)。其次,必须按伙伴系统的方式从free_lists移除这些页,这可能需要分解并重排内存区。内核将该工作委托给前一节提到的buffered_rmqueue。图 阅读全文
posted @ 2022-03-20 21:58 while(true);; 阅读(126) 评论(0) 推荐(0)
摘要:如前所述,__alloc_pages是伙伴系统的主函数。我们已经处理了所有的准备工作并描述了所有可能的标志,现在我们把注意力转向相对复杂的部分:该函数的实现,这也是内核中比较冗长的部分之一。特别是在可用内存太少或逐渐用完时,函数就会比较复杂。如果可用内存足够,则必要的工作会很快完成,就像下述代码。 阅读全文
posted @ 2022-03-20 20:04 while(true);; 阅读(779) 评论(0) 推荐(0)
摘要:所有API函数都追溯到alloc_pages_node,从某种意义上说,该函数是伙伴系统主要实现的“发射台”。 <gfp.h> static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,unsigned int order 阅读全文
posted @ 2022-03-20 18:01 while(true);; 阅读(375) 评论(0) 推荐(0)
摘要:内存域数据结构的初始化工作涉及颇广。幸运的是,该任务在所有体系结构上都是相同的。虽然在2.6.19之前的内核版本必须根据不同的体系结构来建立所需的数据结构,但具体的方法随时间的推移已经越来越模块化。各个体系结构只须注册所有活动内存区的一个简单表,通用代码则据此生成主数据结构。 任何一个体系结构,如果 阅读全文
posted @ 2022-03-20 16:43 while(true);; 阅读(88) 评论(0) 推荐(0)
摘要:直到现在,我们只在特定于体系结构的代码中看到了内核如何检测系统中的可用内存。与高层数据结构(如内存域和结点)的关联,则需要根据该信息构建。我们知道,体系结构相关代码需要在启动期间建立以下信息:  系统中各个内存域的页帧边界,保存在max_zone_pfn数组;  各结点页帧的分配情况,保存在全局 阅读全文
posted @ 2022-03-20 00:51 while(true);; 阅读(166) 评论(0) 推荐(0)
摘要:反碎片的工作原理如何?为理解该方法,我们必须知道内核将已分配页划分为下面3种不同类型。  不可移动页:在内存中有固定位置,不能移动到其他地方。核心内核分配的大多数内存属于该类别。  可回收页:不能直接移动,但可以删除,其内容可以从某些源重新生成。例如,映射自文件 的数据属于该类别。kswapd守 阅读全文
posted @ 2022-03-19 23:40 while(true);; 阅读(212) 评论(0) 推荐(0)
摘要:struct zone { ... /* * 不同长度的空闲区域 */ struct free_area free_area[MAX_ORDER]; ... }; free_area是一个辅助数据结构,我们此前尚未遇见。其定义如下: <mmzone.h> struct free_area { str 阅读全文
posted @ 2022-03-19 22:47 while(true);; 阅读(94) 评论(0) 推荐(0)
摘要:在启动过程期间,尽管内存管理尚未初始化,但内核仍然需要分配内存以创建各种数据结构。bootmem分配器用于在启动阶段早期分配内存。 1. 数据结构 即使最先适配分配器也必须管理一些数据。内核(为系统中的每个结点都)提供了一个bootmem_data结构的实例,用于该用途。当然,该结构所需的内存无法动 阅读全文
posted @ 2022-03-19 19:54 while(true);; 阅读(154) 评论(0) 推荐(0)
摘要:zone_pcp_init负责初始化该缓存。该函数由free_area_init_nodes调用。free_area_init_nodes位置参见setup_arch大概步骤 在用zone_batchsize算出批量大小(用于计算最小和最大填充水平的基础)后,(大约相当于内存域中页数的0.25‰。) 阅读全文
posted @ 2022-03-18 01:51 while(true);; 阅读(108) 评论(0) 推荐(0)
摘要:paging_init负责建立只能用于内核的页表,用户空间无法访问。 在IA-32系统上内核通常将总的4 GiB可用虚拟地址空间按3 : 1的比例划分。低端3 GiB用于用户状态应用程序,而高端的1GiB则专用于内核。  地址空间的划分 地址空间的第一段用于将系统的所有物理内存页映射到内核的虚拟地 阅读全文
posted @ 2022-03-18 01:11 while(true);; 阅读(105) 评论(0) 推荐(0)
摘要:对应高端内存的3部分,高端内存映射有三种方式:映射到”内核动态映射空间”(noncontiguous memory allocation)这种方式很简单,因为通过 vmalloc() ,在”内核动态映射空间”申请内存的时候,就可能从高端内存获得页面(参看 vmalloc 的实现),因此说高端内存有可 阅读全文
posted @ 2022-03-18 01:10 while(true);; 阅读(68) 评论(0) 推荐(0)
摘要:在内核已经载入内存、而初始化的汇编程序部分已经执行完毕后,内核必须执行哪些特定于系统的步骤?图3-12给出了各个操作的代码流程图。 该图只包括与内存管理相关的那些函数调用。在这里所有其他的都是不重要的,因此省去。 首先调用machine_specific_memory_setup,创建一个列表,包括 阅读全文
posted @ 2022-03-18 00:24 while(true);; 阅读(84) 评论(0) 推荐(0)
摘要:图3-11给出物理内存最低几兆字节的布局,以及内核映像的各个部分在其中的驻留情况。 该图给出了物理内存的前几兆字节,具体的长度依赖于内核二进制文件的长度。前4 KiB是第一个页帧,一般会忽略,因为通常保留给BIOS使用。接下来的640 KiB原则上是可用的,但也不用于内 核加载。其原因是,该区域之后 阅读全文
posted @ 2022-03-17 21:13 while(true);; 阅读(98) 评论(0) 推荐(0)
摘要:由于大部分系统都只有一个内存结点,下文只考察此类系统。具体是什么样的情况呢?为确保内存管理代码是可移植的(因此它可以同样用于UMA和NUMA系统),内核在mm/page_alloc.c中定义 了一个pg_data_t实例(称作contig_page_data)管理所有的系统内存。所有平台上都实现了特 阅读全文
posted @ 2022-03-17 21:06 while(true);; 阅读(95) 评论(0) 推荐(0)
摘要:在计算各种水印之前,内核首先确定需要为关键性分配保留的内存空间的最小值。该值随可用内存的大小而非线性增长,并保存在全局变量min_free_kbytes中。用户层可通过文件/proc/sys/vm/min_free_kbytes来读取和修改该设置。 数据结构中水印值的填充由init_per_zone 阅读全文
posted @ 2022-03-17 17:05 while(true);; 阅读(107) 评论(0) 推荐(0)
摘要:图3-3给出了下述内存划分的图示(该情形多少简化了一些,在我们详细讲解数据结构时,读者可以看到这一点)。 首先,内存划分为结点。每个结点关联到系统中的一个处理器,在内核中表示为pg_data_t的实例(稍后定义该数据结构)。各个结点又划分为内存域,是内存的进一步细分。还有一个高端内存区域无法直接映射 阅读全文
posted @ 2022-03-16 22:57 while(true);; 阅读(125) 评论(0) 推荐(0)