一种Linux系统下内存管理方法
【专利摘要】本发明提供一种Linux系统下内存管理方法,在Linux环境下使用大页内存,在大页内存基础上执行内存配置工作过程,内存申请过程和内存释放过程;内存配置工作过程,包括通过计算虚拟地址和物理地址的关系,得到映射的hugepage属于哪个numa节点,并按照物理地址进行排序;内存申请过程包括内存池配置申请和普通内存申请。本发明保持了内存静态分配的高效率的优点,采用2MB的hugepage页取代4kB节省了页的查询时间,并减少TLB miss的可能,而且hugepage内存不会被交换到磁盘上,保证了内存永远为申请的应用程序使用,在内存申请时优先使用本地内存提高了内存访问速度。
【专利说明】
一种L i nux系统下内存管理方法
技术领域
[0001]本发明涉及计算机内存管理技术领域,提供了一种Linux系统下内存管理方法。
【背景技术】
[0002]在Linux系统中,用户通过Iibc的库函数malloc(或类似函数)来在堆上分配内存空间。I ibc对内存的分配有两种途径,分别由两个系统调用函数brl^P_ap来完成。
[0003]在内核中,堆是一个一端固定、一端可伸缩的虚拟地址(vma, virtual memoryaddress)。可伸缩一端通过系统调用函数brk来调整。当进程申请内存小于128k时,使用函数brk分配内存,将_edata(指向数据段最高地址)往高地址推,给进程分配一块内存空间;当进程申请内存大于128k时,使用函数_ap系统调用,在堆和栈之间分配一块虚拟内存。
[0004]此时只分配了虚拟地址,还没有申请物理内存,当第一次向虚拟地址读/写数据时,这时由于没有物理内存的映射,因此CPU会产生一次缺页中断。内核捕获到中断,检查产生中断的地址是不是存在于一个合法的虚拟地址中。如果不是,给进程一个“段错误”,使其崩溃;如果是,则分配一个物理页,并为之建立映射。
[0005]在释放内存时,由_ap分配的内存可以单独释放,由brk分配的内存需要等到高地址内存释放以后才能释放。
[0006]以上就是Linux系统内存管理的流程,但是默认的内存管理函数在通信领域这样需要实时性的应用场景存在一定的不足。
[0007]首先在堆上分配和释放内存会有一些额外的开销。系统在接收到分配一定大小内存的请求时,首先查找内部维护的内存空闲块表,根据一定的算法(例如分配最先找到的不小于申请大小的内存块,或者分配最适于申请的内存块,或者分配最大空闲的内存块)来找到合适大小的空闲内存块。如果该空闲内存块过大,还需要切割成已分配的部分和较小的空闲块。然后系统更新内存空闲块表,完成一次内存分配。
[0008]类似地,在释放内存时,系统把释放的内存块重新加入到空闲内存块表中。如果有可能的话,还要把相邻的空闲块合并成较大的空闲块,但是在前面已经说到brk分配的内存需要高地址内存释放后才能释放,这个时候才能合并空闲块,完成堆的紧缩,在大多数情况下,由于频繁地在堆上分配和释放内存,会导致性能的损失,并且会使系统中出现大量的内存碎片,降低内存使用率。
[0009]默认的内存管理函数还考虑到多线程的应用,需要在每次分配和释放内存时加锁,同样增加了开销。
[0010]另外一个影响性能的重要因素是内存的地址映射,Linux内核使用页式内存管理,应用程序申请的内存地址是虚拟地址,它需要经过若干级页表一级一级的变换,才能变成真正的物理地址,这就意味着实现一次内存访问,实际上内存被访问了N+1次(N=页表级数),并且还需要做N此加法运算。所以地址映射采用了硬件内存管理单元来支持,并且需要有cache(缓存)来保存页表,这个cache就是TLB(Translat1n lookaside buffer,转换后援缓冲器),根据虚拟地址查找物理地址时,首先会从TLB中查找相应的页表数据,如果TLB中正好存放着所需的页表(TLB Hi t),就使用TLB中存放的物理地址,如果TLB没有所需的页表(TLB Mi ss),就必须访问物理内存中存放的页表,同时更新TLB的页表数据。Linux系统默认采用4k为I个页,物理内存较大时会有很多个分页,而TLB的大小有限,可能会发生大量的TLB miss。
[0011]最后,随着科学计算、事物处理对计算机性能要求的不断提高,numa系统的应用越来越广泛,由于访问本地内存资源远远快于远端内存资源,所以在内存分配时,要根据进程所属的numa节点尽量分配本地内存给申请进程。Numa (Non Uniform Memory AccessArchitecture,非统一内存访问架构)技术可以使众多服务器像单一系统那样运转,同时保留小系统便于编程和管理的优点。基于通信领域应用对内存访问提出的更高的要求,对近端、远端内存的访问就是numa系统的难点。
【发明内容】
[0012]本发明目的在于克服现有方法的不足,提供内存管理效率,提供一种Linux系统下的内存管理方法,使用hugepage取代传统的4k页,减少转译查找缓存丢失的可能(TLBmiss),并将hugepage的内存做好地址映射获得物理地址进行排序,找到物理地址所属的CHJ节点,减少远端内存的申请、访问和释放,提高效率。
[0013]本发明的技术方案提供.一种Linux系统下内存管理方法,在Linux环境下使用大页内存,在大页内存基础上执行内存配置工作过程,内存申请过程和内存释放过程,
内存配置工作过程,包括通过计算虚拟地址和物理地址的关系,得到映射的hugepage属于哪个numa节点,并按照物理地址进行排序,
内存申请过程包括内存池配置申请和普通内存申请,通过以下步骤实现,
步骤al,根据内存池的配置,计算每个内存池需要的内存大小以及每个内存池中保存内存块信息的大小;
步骤a2,在numa节点中找到合适的内存分配给各个内存池以及内存池信息记录,然后将内存池初始化,并将相关信息保存到内存池信息记录中;
步骤a3,在应用程序申请内存时,首先判断申请内存是否指定了numa节点,如果指定了numa节点,则在指定numa节点上分配,进行步骤a4 ;未指定numa节点,则在应用程序所属的numa节点上分配,然后进入步骤a4 ;
步骤a4,判断申请大小是否为内存池范围内,如果在范围内,进行步骤a5;如果不在范围内,进行步骤a6;
步骤a5,判断内存池是否存在空闲的内存,如果存在,则分配一块内存给应用程序,修改内存池信息,将该内存块从空闲链中摘去;如果不存在,则从其它numa节点的内存池中申请一块内存,结束本流程;
步骤a6,将hugepage中除去内存池之外的内存都视为free heap,所有申请超过内存池大小的都从free heap中申请,并将内存地址、申请大小保存到内存信息中;
内存释放过程,包括以下步骤,
步骤bl,释放内存时,首先判断要释放的内存是否属于内存池,如果属于内存池,进行步骤b2;如果不属于内存池,进行步骤b3;
步骤b2,此时释放内存属于内存池,将内存重新挂回空闲链,结束本流程; 步骤b3,此时释放内存不属于内存池,则应该属于free heap,根据释放内存地址,得到内存块信息,判断内存是否合法,
如果不合法,进行步骤b4;
如果合法,将内存设置为空闲,并根据内存大小进行偏移,判断上一个内存块是否空闲,如果空闲,则将两块内存合并成一个大的空闲内存,结束本流程;
步骤b4,此时释放内存不合法,退出整个应用程序。
[0014]而且,在Linux环境下使用大页内存,是设置η个2M大小hugepage的物理内存,将hugetlbfs挂载到指定目录。
[0015]而且,内存配置工作过程通过以下步骤实现,
步骤cl,在挂载hugetlbfs的目录下,打开η个文件,每次打开一个文件时,将文件映射到内存,映射区长度为一个hugepage页大小,映射内存区为可写可读,映射标识为共享,得到映射内存的虚拟地址并保存;此次为第一次映射;
步骤c2,若在步骤c I中文件映射失败,则放弃整个内存管理工作,转到步骤c7;若在步骤cl中文件映射成功,则读取/ proc/self/pagemap文件,根据映射内存的虚拟地址计算出hugepage的物理地址并保存;
步骤c3,若在步骤c2中计算hugepage的物理地址失败,则放弃整个内存管理工作,转到步骤c7 ;若在步骤c2中计算hugepage的物理地址成功,贝Ij读取/proc/self/numa_maps文件,取出所有hugepage的虚拟地址以及所在的numa节点,比较numa_maps中的虚拟地址是否和步骤cl中映射的虚拟地址是否相等,如果相等则将numa节点的信息记录下来;
步骤c4,根据hugepage的虚拟地址,对应的物理地址,以及所在的numa节点,再按照物理地址做一次排序;
步骤c5,整理排序后的物理地址,找出连续的物理内存,然后将再次在hugetlbfs的目录下,打开步骤c I中的η个文件,每次打开一个文件时,将文件映射到内存,映射区长度为一个hugepage页大小,映射内存区为可写可读,映射标识为共享,得到映射内存的虚拟地址,此次为第二次映射,此时映射的虚拟地址和物理地址是一样连续的,长度也是相同的;
步骤c6,解除步骤Cl中的第一次映射关系,将第一次映射的虚拟地址空间返回给内核,内存配置工作完成。
[0016]本发明保持了内存静态分配的高效率的优点,采用2MB的hugepage页取代4kB节省了页的查询时间,并减少TLB miss的可能,而且hugepage内存不会被交换到磁盘上,保证了内存永远为申请的应用程序使用,在内存申请时优先使用本地内存提高了内存访问速度。
【附图说明】
[0017]图1为本发明实施例的内存管理结构示意图。
【具体实施方式】
[0018]
以下结合附图和实施例详细说明本发明技术方案。
[0019]本发明实施例提供一种Linux系统下内存管理方法,采用2M的hugepage的物理内存页,减少TLB miss;通过计算虚拟地址和物理地址的关系,得到映射的hug印age属于哪个numa节点,并按照物理地址进行排序,在hugepage中申请定长的内存池;在hugepage中申请free heap;合法的内存释放。
[OO2O]具体包括在Linux操作系统中预先设置η个2M大小hugepage的物理内存,再使用Hugetlbfs文件系统,将预先设置的hugepage物理内存映射到Hugetlbfs挂载的目录下的hugefile文件;通过读取/proc/self/pagemap页面文件,得到本进程中虚拟地址与物理地址的映射关系,将前面提到hugefile文件中的虚拟地址统计页偏移计算得到物理地址,然后将hugepage物理内存按物理地址排序,然后再次映射得到虚拟地址,使虚拟地址也按照物理地址进行排序;根据hugepage物理内存的物理地址查找所属的numa节点,将同一numa节点下的物理内存记录下来;然后在各个numa节点上申请10个内存池,分别为64B、128B、256B、512B、lkB、2kB、4kB、8kB、16kB、32kB,其它内存作为free heap内存;应用模块申请内存时,先判断申请内存是否存在numa节点的要求,如果有,则从指定numa节点的内存池中查找申请内存大小的内存是否存在,如果存在,找到空闲的内存分配给应用模块,如果不存在,则查找其它numa节点中该内存大小空闲最多的内存池,分配一块空闲内存给应用模块,如果申请内存不符合内存池大小要求,则从free heap中申请,找到符合要求的空闲内存给应用模块,找不到符合要求的空闲内存则此次申请失败;当应用模块释放内存时,根据内存信息将内存返回所属的numa节点的内存池或free heap中。
[0021 ]实施例具体实现如下:
首先是在Linux环境下使用大页内存,采用2i^hugepage的物理内存页的实现方法,包括以下步骤:
步骤I,首先根据需要设置η个2M大小hugepage的物理内存,将Linux系统/sys/kernel/mm/hugepage/hugepage~2048kB/nr_hugepages 的倌设詈为η。
[0022]具体实施时,在Linux系统目录/sys/kernel/mm/hugepage/hugepage-2048kB下,将nr_hugepages的值设置为η,即预定了 η个Si^^huagepage物理页。
[0023]具体实施时,η的取值可根据实际物理内存和程序需要申请的物理情况来确定,推荐使用物理内存的一半作为hugepage的内存。
[0024]步骤2,将hugetlbfs挂载到指定目录下,后面会在此目录下生成文件供hugepage来映射。
[0025]Hugepage:在Linux中物理内存时按页(page)划分的,默认情况是每个页4KB,如果物理内存很大,则页数会很多,则映射物理页的条目会非常多,影响CPU的检索效率。为了减少映射物理页的条目,就采取增大页的尺寸的方法,这个就叫做大页(hugepage)。页的范围可以是2MB-1GB,具体依赖于内核版本和硬件架构。
[0026]Hugetlbfs:是Linux中一种文件系统,用于挂载hugepage映射的文件,使该文件系统中的内存操作实现大页调度。
[0027]其次是内存配置工作,即进行虚拟地址和物理地址计算,得到numa节点,物理地址排序,包括以下步骤:
步骤I,在挂载hugetlbfs的目录下,打开η个文件,每次打开一个文件时,将文件映射到内存,映射区长度为一个hugepage页大小,即2MB,映射内存区为可写可读(PR0T_READPR0T_ffRITE),映射标识为共享(MAP_SHARED),得到映射内存的虚拟地址,并将其保存;这是第一次映射; 步骤2,若在步骤I中文件映射失败,则放弃整个内存管理工作,转到步骤7;若在步骤I中文件映射成功,则读取/proc/se If/pagemap文件,根据映射内存的虚拟地址计算出hugepage的物理地址,并将其保存;/proc目录下的文件都是Linux系统的文件,为现有文件,本发明不予赘述;
步骤3,若在步骤2中计算hugepage的物理地址失败,则放弃整个内存管理工作,转到步骤7 ;若在步骤2中计算hugepage的物理地址成功,则读取/ proc/self/numa_maps文件,取出所有hugepage的虚拟地址以及所在的numa节点,比较numa_maps中的虚拟地址是否和步骤I中映射的虚拟地址是否相等,如果相等则将numa节点的信息记录下来;
步骤4,经过前面的步骤后,已经得到了hugepage的虚拟地址,对应的物理地址,以及所在的numa节点,再按照物理地址做一次排序;
步骤5,整理排序后的物理地址,找出连续的物理内存,然后将再次在hugetlbfs的目录下,打开步骤I中的η个文件,每次打开一个文件时,将文件映射到内存,映射区长度为一个hugepage页大小,映射内存区为可写可读(PR0T_READ | PR0T_ffRITE),映射标识为共享(MAP_SHARED),得到映射内存的虚拟地址,此次为第二次映射,此时映射的虚拟地址和物理地址是一样连续的,长度也是相同的;
步骤6,解除步骤I中的第一次映射关系,将第一次映射的虚拟地址空间返回给内核,至此内存配置工作完成,结束本流程;后续将进行内存申请阶段;
如果步骤6内存配置失败,退出内存配置,不再进行后续操作。
[0028]然后是内存申请,包括内存池配置申请和普通内存申请:
步骤1,根据内存池的配置,计算每个内存池需要的内存大小以及每个内存池中保存内存块信息的大小,实施例中内存池分为10个,分别是648、1288、2568、5128、11^、21^、41^、8kB、16kB、32kB;
步骤2,在numa节点中找到合适的内存分配给各个内存池以及内存池信息记录,然后将内存池初始化,并将内存池中地址、序号、空闲链等信息保存到内存池信息记录中;通常保存的信息还有内存池的内存块总数、已使用内存块数目和内存块使用率,用于查看内存使用状态;
步骤3,在应用程序申请内存时,首先判断申请内存是否指定了numa节点,如果指定了numa节点,则在指定numa节点上分配,进行步骤4 ;未指定numa节点,则在应用程序所属的numa节点上分配,然后进入步骤4 ;
步骤4,判断申请大小是否为内存池范围内,如果在范围内,进行步骤5;如果不在范围内,进行步骤6;
步骤5,判断内存池是否存在空闲的内存,如果存在,则分配一块内存给应用程序,修改内存池信息,将该内存块从空闲链中摘去;如果不存在,则从其它numa节点的内存池中申请一块内存,结束本流程;
步骤6,将hugepage中除去内存池之外的内存都视为free heap,所有申请超过内存池大小的都从free heap中申请,并将内存地址、申请大小保存到内存信息中。模拟堆freeheap是自定义的名字,用于区别操作系统的堆heap。功能和操作系统的堆类似,由用户申请和释放任意大小的内存,不同的是申请和释放内存是在hugepage上,而不是操作系统的堆上。
[0029]因为内存池的物理块有大小限制,最大的块为32kB,如果申请的内存大于32kB就不能在内存池中申请,而必须在free heap中申请。
[0030]最后是内存释放:
步骤1,释放内存时,首先判断要释放的内存是否属于内存池,如果属于内存池,进行步骤2;如果不属于内存池,进行步骤3;
步骤2,释放内存属于内存池,将内存重新挂回空闲链,结束本流程;
步骤3,释放内存不属于内存池,则应该属于free heap,根据释放内存地址,得到内存块信息,判断内存是否合法,如果不合法,进行步骤4;如果合法,将内存设置为空闲,并根据内存大小进行偏移,判断上一个内存块是否空闲,如果空闲,则将两块内存合并成一个大的空闲内存,结束本流程;
步骤4,释放内存不合法,退出整个应用程序。
[0031]hugepage的内存主要分为两个部分,一个是内存池,一个是free heap,步骤2是释放内存池的内存,步骤3是释放free heap的内存。
[0032]参见图1,各部分说明如下:
挂载文件:Map_0...Map_n-1为"内存配置工作〃步骤I中的打开文件,使用mmap将文件映射到物理内存;
物理内存:物理内存是η个2M的hugepage的集合,图1上每个2M小方块就是I个hugepage的内存,物理内存中不同样式的内存形式,如具体图例解释。
[0033]memseg(物理内存段):使用mmap映射nfhugepage的物理内存时,物理内存可能不是连续的,可能存在内存空洞,在图1中存在3个内存空洞,所以物理内存被分成了四块,所以有4个memseg,分别指向物理内存的首地址。
[0034]free_memseg(可用物理内存段):是每个memseg中可用内存的首地址,最开始memseg和free_memseg是指向相同的物理内存的,当使用物理内存后,free_memseg指向memseg中未被使用的内存地址,在图1中,第一个memseg指向的是最上面的内存地址,左斜线的内存被内存池使用,f r ee_mems eg就指向内存池下面未被使用的内存。
[0035]mempooI(所有内存池信息保存结构):指向内存池信息的内存,在图1中只有I个内存池信息的内存,所以mempool中只有一条线指向内存池信息的内存。
[0036]内存池信息:记录内存池中各个长度的内存池的地址、使用情况、锁和调试debug信息的内存,便于用户做查找和释放。
[0037]内存池:实际响应用户申请的内存,根据用户申请内存的大小,从不同的长度的内存池中分配内存给用户。
[0038]free_heap(模拟堆):模拟操作系统的堆(heap)工作在hugepage中申请的内存块,free_heap也可以有多个,图1中仅使用一个作为例子。当从free_heap中申请内存时,首先需要在free_heap的开始和结束的内存中申请first elem和last elem两个元素,用来保存申请内存的ig息。
[0039]first elem(模拟堆首元素):保存free heap的低地址,用户申请的内存长度,所属memseg,本块内存是否使用,下块可用内存地址等信息,用于做下一步的内存申请和释放。
[0040]last elem(模拟堆最后元素):保存free heap的高地址,first elem地址等信息,用于做用于保护free heap,防止申请的内存越界。
[0041 ] Map_[ 0-1023 ]文件为hugepage通过mmap映射的挂载文件。即n=l 024。
[0042]因为hugepage的内存可能不是连续的物理内存,所以需要使用memseg记录物理内存的首地址,有多少物理内存段,就有多少个memseg。物理内存段中可能有已经使用的内存和没有使用的内存,没有使用的内存的首地址也被记录到的free_memseg中。
[0043]在分配好的内存池时,会将各个内存池的信息记录在内存池信息的内存中,mempoo I保存的是内存池信息的内存地址。
[0044]free heap是模拟操作系统的堆(heap)功能在hugepage中申请的内存块,当申请内存大小不在内存池范围内时,就从free heap中申请内存。每次在free heap中申请内存时,都会额外多申请一个elem大小的结构,包括保存申请的长度,上一个内存块指针和下一个空闲内存块地址的指针,用以在释放内存时合并空闲内存块。
[0045]上述实施例描述仅为了清楚说明本发明的基本方法和装置,但本发明并不仅限于上述实施例;凡是依据本发明的技术实质上实施例所作的任何简单修改、等同变化与修饰,均落入本发明的技术方案的保护范围之内。
【主权项】
1.一种Linux系统下内存管理方法,其特征在于:在Linux环境下使用大页内存,在大页内存基础上执行内存配置工作过程,内存申请过程和内存释放过程, 内存配置工作过程,包括通过计算虚拟地址和物理地址的关系,得到映射的hugepage属于哪个numa节点,并按照物理地址进行排序, 内存申请过程包括内存池配置申请和普通内存申请,通过以下步骤实现, 步骤al,根据内存池的配置,计算每个内存池需要的内存大小以及每个内存池中保存内存块信息的大小; 步骤a2,在numa节点中找到合适的内存分配给各个内存池以及内存池信息记录,然后将内存池初始化,并将相关信息保存到内存池信息记录中; 步骤a3,在应用程序申请内存时,首先判断申请内存是否指定了numa节点,如果指定了numa节点,则在指定numa节点上分配,进行步骤a4 ;未指定numa节点,则在应用程序所属的numa节点上分配,然后进入步骤a4 ; 步骤a4,判断申请大小是否为内存池范围内,如果在范围内,进行步骤a5;如果不在范围内,进行步骤a6; 步骤a5,判断内存池是否存在空闲的内存,如果存在,则分配一块内存给应用程序,修改内存池信息,将该内存块从空闲链中摘去;如果不存在,则从其它numa节点的内存池中申请一块内存,结束本流程; 步骤a6,将hugepage中除去内存池之外的内存都视为free heap,所有申请超过内存池大小的都从free heap中申请,并将内存地址、申请大小保存到内存信息中; 内存释放过程,包括以下步骤, 步骤bl,释放内存时,首先判断要释放的内存是否属于内存池,如果属于内存池,进行步骤b2;如果不属于内存池,进行步骤b3; 步骤b2,此时释放内存属于内存池,将内存重新挂回空闲链,结束本流程; 步骤b3,此时释放内存不属于内存池,则应该属于free heap,根据释放内存地址,得到内存块信息,判断内存是否合法, 如果不合法,进行步骤b4; 如果合法,将内存设置为空闲,并根据内存大小进行偏移,判断上一个内存块是否空闲,如果空闲,则将两块内存合并成一个大的空闲内存,结束本流程; 步骤b4,此时释放内存不合法,退出整个应用程序。2.根据权利要求1所述Linux系统下内存管理方法,其特征在于:在Linux环境下使用大页内存,是设置η个2M大小hugepage的物理内存,将hugetlbf s挂载到指定目录。3.根据权利要求1或2所述Linux系统下内存管理方法,其特征在于:内存配置工作过程通过以下步骤实现, 步骤cl,在挂载hugetlbfs的目录下,打开η个文件,每次打开一个文件时,将文件映射到内存,映射区长度为一个hugepage页大小,映射内存区为可写可读,映射标识为共享,得到映射内存的虚拟地址并保存;此次为第一次映射; 步骤c2,若在步骤Cl中文件映射失败,则放弃整个内存管理工作,转到步骤c7;若在步骤cl中文件映射成功,则读取/ proc/self/pagemap文件,根据映射内存的虚拟地址计算出hugepage的物理地址并保存; 步骤c3,若在步骤c2中计算hugepage的物理地址失败,则放弃整个内存管理工作,转到步骤c7 ;若在步骤c2中计算hugepage的物理地址成功,贝Ij读取/proc/self/numa_maps文件,取出所有hugepage的虚拟地址以及所在的numa节点,比较numa_maps中的虚拟地址是否和步骤cl中映射的虚拟地址是否相等,如果相等则将numa节点的信息记录下来; 步骤c4,根据hugepage的虚拟地址,对应的物理地址,以及所在的numa节点,再按照物理地址做一次排序; 步骤c5,整理排序后的物理地址,找出连续的物理内存,然后将再次在hugetlbfs的目录下,打开步骤c I中的η个文件,每次打开一个文件时,将文件映射到内存,映射区长度为一个hugepage页大小,映射内存区为可写可读,映射标识为共享,得到映射内存的虚拟地址,此次为第二次映射,此时映射的虚拟地址和物理地址是一样连续的,长度也是相同的; 步骤c6,解除步骤Cl中的第一次映射关系,将第一次映射的虚拟地址空间返回给内核,内存配置工作完成。
【文档编号】G06F12/10GK105893269SQ201610197192
【公开日】2016年8月24日
【申请日】2016年3月31日
【发明人】雷康, 陈亮, 王凤纯, 胡志勇, 肖伟明, 余道敏
【申请人】武汉虹信技术服务有限责任公司