深度详解Linux物理内存组织结构(看完秒懂)

哎,2 02 2 年的那个城市,我正好研究了当时Linux的物理内存组织结构。
这件事相当复杂,所以我必须谈谈。

首先我们要知道,Linux内存是由三层系统管理的,节点、区域和页,就像一个金字塔,最上面是节点,下面是区域,最下面是页。

从架构上来说,有两种可用模式:NUMA 和 SMP。
NUMA 是非统一内存访问。
内存被划分为多个节点。
每个节点都有自己的内存控制器。
处理器访问自己节点的内存速度较快,而节点间访问速度较慢。
SMP的意思是统一内存访问,所有处理器访问内存的延迟是相同的。

例如,在x8 6 这样的系统中,CPU芯片上有多个插槽。
每个socket就是一个节点,内存访问速度最快的就是该节点上的内存。

内存模型分为三种类型:平坦、不连续和稀疏。
这三种模式决定了如何选择内存分配算法。

扁平内存拥有连续无洞的地址空间,就像一块大蛋糕。
内核通过 mem_map 数组管理所有页帧,这是分配效率最高的。

在不连续内存中,地址空间中存在漏洞。
例如,硬件保留了某些区域或内存插槽未满。
内核会将节点划分为连续的块,每个节点都有自己的mem_map。

稀疏内存,基于不连续内存,支持内存热插拔,通过虚拟内存映射动态管理页框。
即使牺牲一点性能,它也会获得灵活性。

然后是一个三级结构,节点、区域和页面。
节点就像社区,区域就像社区的不同区域,页面就像社区中的建筑物。

从节点端来看,NUMA节点在物理上与CPU和内存相邻。
每个节点都有自己的pglist_data结构,它描述了这个节点的内存区域。
UMA节点意味着整个系统是一个节点。

从区域方面来看,比如DMA区域、Normal区域和HighMEM区域,每个区域对应不同的内存使用场景。

页是内存的最小单位。
它是通过 structpage 来描述的。
页面描述符包含页面状态、引用计数、映射关系等信息。

要分配和回收内存,需要使用伙伴系统,该系统按 2 的幂合并和拆分空闲页帧,以减少外部碎片。
还有 Slab 分配器,它处理内核对象,例如 task_struct 和 inode。
它通过kmem_cache_create创建缓存池,分配和释放效率非常高。

这里的关键系统调用,如mmap和munmap,mmap创建虚拟内存映射,munmap消除内存映射。

综上所述,Linux物理内存组织结构通过三级分层和两种架构的协作,实现了高性能和可扩展性之间的平衡。
对于内核开发和系统运维来说,理解这个结构很重要。

Linux内存分配算法

等等,我正在帮助一个朋友修理他的电脑,他的电脑像蜗牛一样关闭了。
我打开任务管理器,发现内存使用量超出了图表;多个进程正在竞争内存。
我意识到内存管理不是简单的分配和串联问题,而是其背后的算法很复杂。

Buddy算法很简单,将块分成块。
但实际上维护这些链表就让我光是想想就头疼。
在我公司编写内存管理工具时,我调试了 Buddy 算法,发现在连接相邻内存块时指针多次出现混淆。
我花了一整夜才弄清楚。
在2 02 1 年的项目中,我们改变了Buddy的分区策略来优化内存分区。
因此,分配延迟会意外增加。
真的很酷。

Slab 算法将小对象堆叠在一起,没有任何实际问题。
然而,当我上次测试系统时,当Slab回收对象时;当缓存已满时,将继续创建新的Slab。
因为新的 Slab 会不断被创建。
哪个参数设置错误?我们在实验室的台式计算机上对其进行了多次测试以找出答案。
我们仍然记得屏幕上的红色错误消息。

虚拟内存的分页机制更奇怪。
我的客户端计算机的虚拟内存配置太小。
结果,当进程访问大文件时;反复更改页表会使 CPU 使用率高达 9 0%。
对于 2 02 2 年的项目,我们向他的系统添加了 2 GB 交换空间,这实际上解决了问题。
我当时觉得这难以置信。
Linux内核的vmalloc函数很奇怪。
分配的内存对于进程来说是连续的,但是当查看物理内存时,发现它在系统中是分散的。
这就像给程序员画饼图一样;吃的时候才发现馅料坏了。

现在想一想,内存管理就像做饭吗? Buddy算法是流水线操作,Slab是一批预先准备好的板材,而分页则以不同的方式使用配料。
但人们的需求很奇怪。
有时他们想吃现成的食物,有时他们想煮一整锅。
Linux 将这些算法内置到内核中。
在什么情况下是最好的解决方案?

CentOS下SWAP分区建立及释放内存详解

创建SWAP分区有两种方法,一种是使用文件,另一种是使用磁盘。

文件方法是最简单的。
首次使用时免费检查内存。
然后添加 if=/dev/zero of=/swapfile bs=1 M count=1 02 4 创建一个 1 G 的交换文件。
使用 mkswap /swapfile 进行格式化。
使用 swapon /swapfile 启用它。
最后编辑/etc/fstab,添加一行/swapfile swap swap defaults 0 0。

磁盘方法稍微复杂一些。
首先使用免费查看SWAP。
使用 swapoff /dev/sdXY 停止旧分区。
使用fdisk删除然后分割。
使用 mkswap /dev/sdXY 进行格式化。
使用 swapon /dev/sdXY 来启用它。
更改 /etc/fstab.conf
释放内存只有两种方法。
echo 3 > /proc/sys/vm/drop_caches 可以清除缓存。
但进程占用的内存是无法擦除的。

每天0:00自动清除缓存。
编写脚本 /bin/sync &&sync && echo 3 > /proc/sys/vm/drop_caches。
使用 crontab -e 添加 0 0 /path/script。
自己去了解一下效果如何。