前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[linux][memory] 物理内存管理

[linux][memory] 物理内存管理

作者头像
皮振伟
发布2018-04-09 11:23:50
2.6K0
发布2018-04-09 11:23:50
举报
文章被收录于专栏:皮振伟的专栏皮振伟的专栏

前言: 书接上回《内存映射技术分析》,继续来分析一下linux的物理内存管理。 分析: 1,物理内存 PC上的内存条,或者手机上的内存芯片,物理上实实在在的内存,就是物理内存。大小是硬件决定的,一般就是一个起始地址,加上大小。地址如何分配呢?PC上作者也不太懂,听闻BIOS可以配置。在ARM上,作者曾经看过一份电路图,当时的图上,使用32bit的高2bit作为chip select,后面的30bit作为地址总线,看过chip select信号之后,作者才明白为什么在代码上要配置起始的地址不是0,因为硬件是这么连接的。。。Orz 2,e820 使用dmesg查看内核log: 从时间上也看得出来,在kernel启动的早期阶段,会得到物理内存的RAM map。

在/boot/grub/grub.cfg中,增加 memblock=debug,可以得到更多的memblock的log:

3,node 内存上,还有一个概念,就是node。一台机器上,含有一个或者多个node。 含有一个node的是UMA,含有多个node的是NUMA。 node编号从0开始。在UMA上,其实也是使用NUMA模型,只是说,只有一个node 0。 4,zone 一个node中,含有一个或者多个zone。 还是dmesg:

作者的机器是64bit的。32bit和64bit还有挺大区别的。 原因在于:32bit的机器上,虚拟地址空间只有4G,linux默认把低3G给用户用,把高1G给kernel用。那么kernel要想访问内存,最多只能映射1G,这个明显不合理。所以kernel把高于896M的物理内存标记为High Memory Zone,访问High Memory Zone的内存就不能使用固定映射了,需要动态映射。 在64bit机器上则不存在这个问题,虚拟地址空间有2的64次方之大。 5,watermark 俗称“水线”,在分配page之前,先要检查watermark。如果低于watermark了,说明系统内存不太多了,要适当回收。 6,buddy system Linux的内存管理的核心算法,就是“伙伴系统”。2个连续的page(绝大多数情况下,一个page是4K)的就是一个连续的8k,它的order是1;4个连续的page的就是一个连续的16k,它的order是2;依次类推,一直到4M。 其实,buddy system的代码还是比较容易看懂的。在linux-4.0.4/mm/page_alloc.c中:

其中MAX_ORDER是11,所以order最大也就是10,因此linux上从buddy system可以申请最大的连续内存就是4M。但是,并不代表一定可以申请成功。比如说,2M的没有了,就需要把4M的内存分成两个2M的,其中一个分配出去,一起保存在2M的list中。时间长了,就会出现很多小块的内存,就是所谓的内存碎片。这里需要说明一下,对于Linux来说,一般都不需要连续的内存,因为系统跑起来之后,CPU在protected mode下访问的是虚拟地址,MMU把不连续的物理地址映射成连续的虚拟地址就可以了。但是,对于很多硬件来说,比如xx厂家的网卡,它没有MMU,可能就需要申请连续的一块内存,这里是存在分配失败的风险的。当然,可能通过cat /proc/meminfo看到有很多free,但是它们可能不连续。 7,hot page & cold page Linux中,释放page,并不是直接归还给buddy system。会把它保存在per cpu的pageset中,它就是一个做cache用的链表。当然,这个链表上的page的order都是0。 在linux-4.0.4/mm/page_alloc.c中:

order为0的情况下,优先选择从pageset中申请。cold和hot的的区别就是从list的尾部还是头部分配page。因为回收的时候,会选择放在头部,所以,从头部拿page,这个page是“hot”的---根据局部性原理,那么这个page很可能还在CPU的cache中,造成cache miss的概率会降低。 8,CMA Contiguous Memory Allocator,连续内存分配器。一般针对嵌入式平台,用来分配连续的大量内存,可能远远大于buddy system的最大值4M。比如说手机播放视频的时候,使用硬件decode,video decoder可能没有MMU,那么就需要大量的连续物理内存了,就需要使用CMA来分配。 这里的代码不分析了,网上也会比较多。而且在服务器上也一般不会使用到。 9,slab 内核中分配内存的最小单位是page。但是,很多数据结构只有几十byte。第一是浪费空间,第二是分配/回收page的代价太高。于是就有了slab。slab的大概实现:申请一段内存,把它分成n个xx类型的数据结构那么大,每次申请的时候,直接从这个cache里面拿就行了,加快了分配速度。当然,slab的管理更复杂一些,包括使用一个bitmap来管理所有的instance,并可以在一个类型的slab中注册构造函数和析构函数,并且slab也要支持回收。 在shell中敲slabtop:

如图,哪些slab用了多少,每个占用多少,一目了然。比如说互联网服务器上,它的skb肯定很多,小文件很多的机器上,它的inode占用肯定要多一些。 10,sparse mem 物理内存上,如果存在巨大的hole,可以考虑使用sparse mem。 就是说,让Linux在管理这些memory block的时候,跳开两个不连续的block中间的hole,节省一些page struct占用的内存。 后记: 好吧,这里还是在为MMIO做准备,没有铺开讲具体细节。 内存管理是Linux的一个重点,也算是难点。熟悉并了解需要花些时间。作者当时也是夜深人静的时候printk打log一点一点看的。。。Orz 欢迎留言讨论。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-02-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AlwaysGeek 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档