searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

linux 物理内存管理

2023-03-30 08:43:50
67
0

前言

大家有没有发现在linux系统中通过free显示的内存(total)比物理内存少,比如我的一台16384M(16G)内存的host, 通过free显示只有15300M:

图-1

只是什么原因造成的呢,剩余的内存又到哪去了呢?

以下作者将以linux4.19代码为例详细说明linux对物理内存的管理。

Linux是怎么识别到内存的

针对linux系统来说,内存的信息是通过e820获取的,内核通过 detect_memory()函数实现对真实物理内存的探测,具体方法为通过0x15 中断向BIOS查询获取

代码-1

 

获取到的内存信息保存在e820_table中,

在获取到e820_table之后,系统会调用e820__memblock_setup函数,将e820内存信息加入到memblock中,具体实现如下:

代码-2

 

这里以作者的16384M内存主机为利,通过e820获取的内存大小会小于16384M,主要原因是BIOS,EFI,SMM等会占用一部分内存。在我的16384M内存的主机上e820识别到的内存加入memblock的总大小是16165M。

图-2

 

16165M和free显示的15300M还差了865M,那这部分内存又都哪去了呢?

其实这和linux对内存的使用管理有关。

memblock对物理内存的管理

代码-3

 

从memblock结构体的定义可知,memblock有两种类型的内存,一是memory,是所有内存(16951214080Byte),这里size的单位为Byte, 转化成MB刚好是16165M。

图-3

 

另一种是reserved,被标记为reserved的内存不能被分配使用,主要由两部分组成,1是内核启动过程中内核代码和数据所使用的内存,这部分内存是系统的关键代码及数据需要长期保留;2是标准规定的必须保留的内存,比如0号页框内存等。

 那reserved是否就是16165M -15300M =865M呢?

图-4

 

图-5

 

reserved的大小是1048989458Byte = 1000M, 比865M还多了135M,那free又是怎么得到的呢?

 

free total memory的计算

首先通过free_all_bootmem计算totalram_pages,其方法为在free_low_memory_core_early函数中统计在memblock.memory中且不在memblock.reserved中的内存。

代码-4

 

通过打印count数值,这里count为3882543,大小为3882543*4K = 15902896128Byte=15166M。这个数字比free显示的total小。

图-6

 

其原因是启动过程中分配的部分被标记为__init的函数和数据内存,在系统启动成功后会被回收,可以再次被使用,这部分内存会重新加入totalram_pages。

其代码路径为free_init_pages—>free_reserved_area-->free_reserved_page--> adjust_managed_page_count,其最终通过adjust_managed_page_count函数增加totalram_pages的数量,totalram_pages就是free显示时的total大小。

代码-5

代码-6

代码-7

代码-8

最终totalram_pages 为在memblock.memory中且不在memblock.reserved中的内存,加上被释放的标记为__init的内存,也就是free中total显示的内存数量。那memblock.reserved中又主要是哪些内存呢?

memblock.reserved中的主要内存

memblock.reserved中的内存主要是启动过程中分配的内核使用的内存数据,刚启动时,slab等内核分配函数还不能使用,此时分配内存主要通过memblock_alloc在memblock中分配,方法为在memblock.memory中找到一个合适大小的内存块,将其加入memblock.reserved中。其主要被以下几方面使用,

crashkernel: 其大小和系统对crashkernel的配置有关,分配函数为reserve_crashkernel_low -- > memblock_reserve

在作者本机上crashkernel 配置为512M。

 

page_struct: page_struct是物理内存的的管理结构,一个page_struct结构大小在4.19内核中为64Byte, 管理16165M内核大约需要253M内存来保存page_struct,此外在作者本机上page_struct管理方法使用SPARSEMEM_VMEMMAP方式管理,其还需要额外的内存用于page table映射。

针对page_struct的管理一共有4种不同的内存模型,并为每个内存模型都定义了 pfn_to_page() 和 page_to_pfn() 帮助函数,允许从PFN到 struct page 的转换,反之亦然。

FLATMEM:这个模型适用于非NUMA系统的连续或大部分连续的 物理内存,所有page_struct在一个全局数组中,使用mem_map数组表示;

DISCONTIGMEM:针对numa等非连续存储空间的早期实现,把全局的mem_map分散在numa的pglist_data结构体中,相当于每个numa一个数组;

SPARSEMEM:非连续稀疏存储空间实现,在每个numa中,内存也不连续,或为了支持内存热插拔等高级功能,如果使用一个数组表示会有很大的浪费。SPARSEMEM使用额外的一层结构struct mem_section,每个mem_section一个数组来组织本section的物理内存。

SPARSEMEM_VMEMMAP:在SPARSEMEM的基础上,使用虚拟地址映射的方式来实现pfn/page之间的转换,提高转换效率,以及减少了page_struct中flag的占用。

实现虚拟地址映射的关键函数为sparse_init_nid。

此函数会为每个mem_section分配对应的映射页表:对于存在的物理页,为其分配对应的保存page_struct的空间,

这四种转换的相关函数见include/asm-generic/memory_model.h文件,有兴趣的同学可以看看。

 

除了crashkernel, page struct使用的内存外,memblock.reserved中还包括其他内核启动过程中的代码及数据,比如,启动代码使用的内存,在slab开启之前,代码允许需要的数据,标准协议规定的报留内存等。

总结

综上所述,物理内存比多个原因造成的。

以作者使用的这台16G内存主机为例,物理内存的使用总计分为以下几类(系统总计内存为16G(16384M)):

BIOS,EFI,SMM等非系统占用16384M-16165M= 219M

系统reserved 内存1000M,  分为 _init标记的内存 135M, 不是__init标记的内存865M(包括crashkernel 512M , page struct 253M, 没有被__init标识的剩下的早期分配的被记录在memblock.reserved中的内存100M)

剩下的15300M记录在free total中(包括系统reserved 内存且是__init标记的内存 135M)。

0条评论
0 / 1000
刘强
6文章数
2粉丝数
刘强
6 文章 | 2 粉丝
原创

linux 物理内存管理

2023-03-30 08:43:50
67
0

前言

大家有没有发现在linux系统中通过free显示的内存(total)比物理内存少,比如我的一台16384M(16G)内存的host, 通过free显示只有15300M:

图-1

只是什么原因造成的呢,剩余的内存又到哪去了呢?

以下作者将以linux4.19代码为例详细说明linux对物理内存的管理。

Linux是怎么识别到内存的

针对linux系统来说,内存的信息是通过e820获取的,内核通过 detect_memory()函数实现对真实物理内存的探测,具体方法为通过0x15 中断向BIOS查询获取

代码-1

 

获取到的内存信息保存在e820_table中,

在获取到e820_table之后,系统会调用e820__memblock_setup函数,将e820内存信息加入到memblock中,具体实现如下:

代码-2

 

这里以作者的16384M内存主机为利,通过e820获取的内存大小会小于16384M,主要原因是BIOS,EFI,SMM等会占用一部分内存。在我的16384M内存的主机上e820识别到的内存加入memblock的总大小是16165M。

图-2

 

16165M和free显示的15300M还差了865M,那这部分内存又都哪去了呢?

其实这和linux对内存的使用管理有关。

memblock对物理内存的管理

代码-3

 

从memblock结构体的定义可知,memblock有两种类型的内存,一是memory,是所有内存(16951214080Byte),这里size的单位为Byte, 转化成MB刚好是16165M。

图-3

 

另一种是reserved,被标记为reserved的内存不能被分配使用,主要由两部分组成,1是内核启动过程中内核代码和数据所使用的内存,这部分内存是系统的关键代码及数据需要长期保留;2是标准规定的必须保留的内存,比如0号页框内存等。

 那reserved是否就是16165M -15300M =865M呢?

图-4

 

图-5

 

reserved的大小是1048989458Byte = 1000M, 比865M还多了135M,那free又是怎么得到的呢?

 

free total memory的计算

首先通过free_all_bootmem计算totalram_pages,其方法为在free_low_memory_core_early函数中统计在memblock.memory中且不在memblock.reserved中的内存。

代码-4

 

通过打印count数值,这里count为3882543,大小为3882543*4K = 15902896128Byte=15166M。这个数字比free显示的total小。

图-6

 

其原因是启动过程中分配的部分被标记为__init的函数和数据内存,在系统启动成功后会被回收,可以再次被使用,这部分内存会重新加入totalram_pages。

其代码路径为free_init_pages—>free_reserved_area-->free_reserved_page--> adjust_managed_page_count,其最终通过adjust_managed_page_count函数增加totalram_pages的数量,totalram_pages就是free显示时的total大小。

代码-5

代码-6

代码-7

代码-8

最终totalram_pages 为在memblock.memory中且不在memblock.reserved中的内存,加上被释放的标记为__init的内存,也就是free中total显示的内存数量。那memblock.reserved中又主要是哪些内存呢?

memblock.reserved中的主要内存

memblock.reserved中的内存主要是启动过程中分配的内核使用的内存数据,刚启动时,slab等内核分配函数还不能使用,此时分配内存主要通过memblock_alloc在memblock中分配,方法为在memblock.memory中找到一个合适大小的内存块,将其加入memblock.reserved中。其主要被以下几方面使用,

crashkernel: 其大小和系统对crashkernel的配置有关,分配函数为reserve_crashkernel_low -- > memblock_reserve

在作者本机上crashkernel 配置为512M。

 

page_struct: page_struct是物理内存的的管理结构,一个page_struct结构大小在4.19内核中为64Byte, 管理16165M内核大约需要253M内存来保存page_struct,此外在作者本机上page_struct管理方法使用SPARSEMEM_VMEMMAP方式管理,其还需要额外的内存用于page table映射。

针对page_struct的管理一共有4种不同的内存模型,并为每个内存模型都定义了 pfn_to_page() 和 page_to_pfn() 帮助函数,允许从PFN到 struct page 的转换,反之亦然。

FLATMEM:这个模型适用于非NUMA系统的连续或大部分连续的 物理内存,所有page_struct在一个全局数组中,使用mem_map数组表示;

DISCONTIGMEM:针对numa等非连续存储空间的早期实现,把全局的mem_map分散在numa的pglist_data结构体中,相当于每个numa一个数组;

SPARSEMEM:非连续稀疏存储空间实现,在每个numa中,内存也不连续,或为了支持内存热插拔等高级功能,如果使用一个数组表示会有很大的浪费。SPARSEMEM使用额外的一层结构struct mem_section,每个mem_section一个数组来组织本section的物理内存。

SPARSEMEM_VMEMMAP:在SPARSEMEM的基础上,使用虚拟地址映射的方式来实现pfn/page之间的转换,提高转换效率,以及减少了page_struct中flag的占用。

实现虚拟地址映射的关键函数为sparse_init_nid。

此函数会为每个mem_section分配对应的映射页表:对于存在的物理页,为其分配对应的保存page_struct的空间,

这四种转换的相关函数见include/asm-generic/memory_model.h文件,有兴趣的同学可以看看。

 

除了crashkernel, page struct使用的内存外,memblock.reserved中还包括其他内核启动过程中的代码及数据,比如,启动代码使用的内存,在slab开启之前,代码允许需要的数据,标准协议规定的报留内存等。

总结

综上所述,物理内存比多个原因造成的。

以作者使用的这台16G内存主机为例,物理内存的使用总计分为以下几类(系统总计内存为16G(16384M)):

BIOS,EFI,SMM等非系统占用16384M-16165M= 219M

系统reserved 内存1000M,  分为 _init标记的内存 135M, 不是__init标记的内存865M(包括crashkernel 512M , page struct 253M, 没有被__init标识的剩下的早期分配的被记录在memblock.reserved中的内存100M)

剩下的15300M记录在free total中(包括系统reserved 内存且是__init标记的内存 135M)。

文章来自个人专栏
内核
6 文章 | 1 订阅
0条评论
0 / 1000
请输入你的评论
0
0