1.Linux内核:内存管理——Slab分配器
2.高性能BPF内存分析工具解析
3.Linux中的源码内存分配--slab(1)
4.Linux内核源码解析---万字解析从设计模式推演per-cpu实现原理
5.Linux三大分配器之浅析slab基本原理
6.linux查看cpu占用率的方法:
Linux内核:内存管理——Slab分配器
深入解析Linux内核:内存管理的艺术——SLAB分配器
在Linux内核的世界里,内存管理是分析一项至关重要的任务。其中,源码SLAB分配器扮演着关键角色,分析它解决了页框分配器的源码大页框浪费问题,通过专用SLAB(如TCP)和普通SLAB(如kmalloc-8,分析棋牌站源码 kmalloc-等)实现了高效而灵活的内存管理。通过执行`cat /proc/slabinfo`,源码我们可以窥探SLAB的分析运行状态。
SLAB的源码核心理念在于对象大小的固定性,这有助于减少内存碎片,分析提高内存使用效率。源码kmem_cache(SLAB缓存)是分析其最高层级的数据结构,它负责描述和管理SLAB及其对象。源码内核模块通过kmem_cache_create定制化的分析SLAB,确保内存管理的源码灵活性。
kmem_cache结构内部,对象大小(object_size)与SLAB的全局配置如gfporder和num保持同步。每个NUMA节点的SLAB管理由struct kmem_cache_node数组负责,它支持分布式内存管理,确保了内存的均衡分配。
在kmem_cache的内部结构中,SLAB链表是关键部分,包括slabs_partial、slabs_full和slabs_free。slabs_partial存储部分使用的SLAB描述符,slabs_full则是所有对象的链表,而slabs_free则记录空闲的SLAB。这些链表通过spinlock_t lock进行同步,确保了在分配和回收过程中的线程安全。
SLAB设计巧妙,如SLUB(Simple Low Overhead Buffering)和SLOB(Simplified Low Overhead Buffering)结构,它们结合了计数器、活跃对象和动态链表,以实现内存的高效分配。SLAB描述符还包括页标志、对象地址指针和空闲对象链表,这些细节都在CONFIG_SLUB配置中有所体现。
SLAB描述符中的freelist和填充区域的优化,以及对象地址的着色设计,都是提高内存利用率的重要手段。内存着色通过添加偏移量避免同一行内存冲突,提升了性能。本地CPU和共享链表的组合,形成了SLAB分配器的高效运作框架,优先级分配原则保证了快速响应。
了解这些细节后,xcode打印源码我们发现SLAB分配器是Linux内核内存管理的精髓所在,它在内存分配和回收的过程中,巧妙地平衡了效率与灵活性。通过深入研究这些内部机制,我们可以更好地理解和优化我们的系统内存使用。
推荐阅读
1. Linux文件系统详解
2. Linux进程管理:实时调度
3. Linux内核内存管理 - 缺页异常 & brk系统调用
原文作者:tolimit
原文地址:linux内存源码分析 - SLAB分配器概述
---
经过上述的精炼与重构,文章内容更加清晰,突出了SLAB分配器在Linux内核内存管理中的核心作用和关键细节,为读者提供了深入理解内存管理的窗口。
高性能BPF内存分析工具解析
Linux内核与CPU处理器协同工作,将虚拟内存映射到物理内存,以提升效率。内存管理通过创建内存映射的页组来实现,每页大小根据处理器实际情况设定,通常为4 KB。内核从页空闲列表分配物理内存页,优化分配策略以提高效率。分配器如slab分配器从空闲列表使用内存。
典型的内存页面管理过程包括申请、分配、存储和释放。繁忙应用中,用户层内存分配频繁,指令执行和MMU查找大量发生,对内存管理构成挑战。系统通过定期激活kswapd,检查空闲与活跃页面,释放内存以应对内存压力。kswapd协调后台页面召回,降低性能影响,但可能引起CPU和磁盘I/O竞争。当内存回收受限,分配将被阻塞,并同步等待内存释放。内核shrinker函数触发直接回收,释放内存,减少缓存占用。
内存不足时,swap设备提供解决方案,允许进程继续分配内存,将不常用页面交换至swap,但会导致性能下降。关键系统倾向于避免使用swap,以防止内存不足导致进程被杀。内存不足情况下,圈子棋牌源码oom killer作为内存释放的最后手段,通过规则选择牺牲进程。通过调整系统和进程配置,优化内存管理。
随着内存碎片化加剧,内核启动页面压缩与移动,释放连续内存空间。Linux文件系统利用空闲内存缓存数据,通过调整参数vm.swappiness,系统可以选择从文件缓存或swap释放内存。传统性能工具提供内存使用统计,但分析内存使用情况需要更深入理解,如page fault率、库分配等。BPF工具如kmem、kpages、slabratetop、numamove,以及oomkill和memleak,通过更高效、性能损耗更低的方式进行内存分析。
BPF相关工具提供内存分析能力,包括跟踪内存分配与释放事件、检测内存泄漏等。oomkill用于监控并打印oom killer事件详细信息,memleak跟踪内存分配与释放,辅助内存问题诊断。BPF工具为内存管理提供强大支持,结合源代码分析,可有效识别并解决内存问题。
Linux中的内存分配--slab(1)
在Linux中,当内存分配遇到小于一页的需求时,为避免浪费和内碎片问题,slab分配器应运而生。slab分配器的核心机制是kmem_cache,它为每个对象类别维护一个"cache",分配和释放对象时都从对应的cache中进行,提高了效率。cache的内存来源于buddy伙伴系统,通过分页并按照对象大小划分,确保物理内存的连续性。
每个kmem_cache由若干slabs组成,每个slab由一个或多个页框构成,大小由gfporder定义。为了优化CPU缓存利用,yy模块源码slab引入了coloring机制,通过调整slab中的偏移量,确保相同对象号的对象不会对齐,从而减少缓存替换操作。
kmem_cache_node负责描述和管理slab中的对象,包含slab链表,根据NUMA架构进行内存分配。slab描述符中,s_mem和freelist分别指向第一个对象和空闲对象链表。空闲对象链表由数组组成,根据活跃对象动态调整。
本地CPU空闲链表作为kmem_cache的一部分,记录对象的释放,便于内存回收。通过slabtop命令,可以查看系统的slab分配情况,包括内存使用、cache数量、slabs数量以及object大小分布。此外,/proc/meminfo和/proc/slabinfo提供了更详细的内存使用信息。
深入理解slab分配器的更多内容,可以参考相关文章如《Slab Allocator (kernel.org)》、《The Slab Allocator in the Linux kernel (hammertux.github.io)》以及《linux内存源码分析 - SLAB分配器概述》等。
Linux内核源码解析---万字解析从设计模式推演per-cpu实现原理
引子
在如今的大型服务器中,NUMA架构扮演着关键角色。它允许系统拥有多个物理CPU,不同NUMA节点之间通过QPI通信。虽然硬件连接细节在此不作深入讨论,但需明白每个CPU优先访问本节点内存,当本地内存不足时,可向其他节点申请。从传统的SMP架构转向NUMA架构,主要是为了解决随着CPU数量增多而带来的总线压力问题。
分配物理内存时,numa_node_id() 方法用于查询当前CPU所在的NUMA节点。频繁的内存申请操作促使Linux内核采用per-cpu实现,将CPU访问的变量复制到每个CPU中,以减少缓存行竞争和False Sharing,类似于Java中的Thread Local。
分配物理页
尽管我们不必关注底层实现,buddy system负责分配物理页,关键在于使用了numa_node_id方法。接下来,我们将深入探索整个Linux内核的chromium 49源码per-cpu体系。
numa_node_id源码分析获取数据
在topology.h中,我们发现使用了raw_cpu_read函数,传入了numa_node参数。接下来,我们来了解numa_node的定义。
在topology.h中定义了numa_node。我们继续跟踪DECLARE_PER_CPU_SECTION的定义,最终揭示numa_node是一个共享全局变量,类型为int,存储在.data..percpu段中。
在percpu-defs.h中,numa_node被放置在ELF文件的.data..percpu段中,这些段在运行阶段即为段。接下来,我们返回raw_cpu_read方法。
在percpu-defs.h中,我们继续跟进__pcpu_size_call_return方法,此方法根据per-cpu变量的大小生成回调函数。对于numa_node的int类型,最终拼接得到的是raw_cpu_read_4方法。
在percpu.h中,调用了一般的read方法。在percpu.h中,获取numa_node的绝对地址,并通过raw_cpu_ptr方法。
在percpu-defs.h中,我们略过验证指针的环节,追踪arch_raw_cpu_ptr方法。接下来,我们来看x架构的实现。
在percpu.h中,使用汇编获取this_cpu_off的地址,代表此CPU内存副本到".data..percpu"的偏移量。加上numa_node相对于原始内存副本的偏移量,最终通过解引用获得真正内存地址内的值。
对于其他架构,实现方式相似,通过获取自己CPU的偏移量,最终通过相对偏移得到pcp变量的地址。
放入数据
讨论Linux内核启动过程时,我们不得不关注per-cpu的值是如何被放入的。
在main.c中,我们以x实现为例进行分析。通过setup_percpu.c文件中的代码,我们将node值赋给每个CPU的numa_node地址处。具体计算方法通过early_cpu_to_node实现,此处不作展开。
在percpu-defs.h中,我们来看看如何获取每个CPU的numa_node地址,最终还是通过简单的偏移获取。需要注意如何获取每个CPU的副本偏移地址。
在percpu.h中,我们发现一个关键数组__per_cpu_offset,其中保存了每个CPU副本的偏移值,通过CPU的索引来查找。
接下来,我们来设计PER CPU模块。
设计一个全面的PER CPU架构,它支持UMA或NUMA架构。我们设计了一个包含NUMA节点的结构体,内部管理所有CPU。为每个CPU创建副本,其中存储所有per-cpu变量。静态数据在编译时放入原始数据段,动态数据在运行时生成。
最后,我们回到setup_per_cpu_areas方法的分析。在setup_percpu.c中,我们详细探讨了关键方法pcpu_embed_first_chunk。此方法管理group、unit、静态、保留、动态区域。
通过percpu.c中的关键变量__per_cpu_load和vmlinux.lds.S的链接脚本,我们了解了per-cpu加载时的地址符号。PERCPU_INPUT宏定义了静态原始数据的起始和结束符号。
接下来,我们关注如何分配per-cpu元数据信息pcpu_alloc_info。percpu.c中的方法执行后,元数据分配如下图所示。
接着,我们分析pcpu_alloc_alloc_info的方法,完成元数据分配。
在pcpu_setup_first_chunk方法中,我们看到分配的smap和dmap在后期将通过slab再次分配。
在main.c的mm_init中,我们关注重点区域,完成map数组的slab分配。
至此,我们探讨了Linux内核中per-cpu实现的原理,从设计到源码分析,全面展现了这一关键机制在现代服务器架构中的作用。
Linux三大分配器之浅析slab基本原理
Linux内核中的内存分配管理涉及到Buddy和SLAB两种机制。Buddy分配器虽提供了page级别的接口,但颗粒度依然偏大,因此需要SLAB来进一步细化管理。SLAB分配器主要分为slab、slub和slob,其中slob适用于内存紧张的嵌入式系统,而slab因其效率和通用性,是Linux内核中的核心部分。
SLAB的管理涉及两个关键结构:kmem_cache(缓存)和slab本身,它们之间通过cache_chain相连。在内核初始化时,会根据kmalloc_sizes.h中的定义创建特定大小obj的slab和kmem_cache,称为通用缓存,供kmalloc使用。kmalloc通过查找最接近输入size的kmem_cache来分配内存,可能导致内存浪费。
SLAB分配器的复杂性体现在其两个重要数据结构:per node和per cpu的kmem_list3和array_cache。kmem_list3管理slab的分配状态,而array_cache负责按cpu缓存obj。slab结构分为内嵌式和外挂式,管理数据kmem_bufctl_t记录当前和下一个可用obj的位置。分配流程优先从array_cache中LIFO原则获取,释放时则优先回放在array_cache,超出limit后才会移动到kmem_list3。
深入理解SLAB分配器的原理和管理逻辑对于优化内存使用和性能至关重要。对于更深入的学习资源,可以加入作者推荐的Linux内核技术交流群获取更多信息和资料,包括内核源码、内存调优等内容。
linux查看cpu占用率的方法:
top
top是最常用的查看系统资源使用情况的工具,包括CPU、内存等等资源。这里主要关注CPU资源。
1.1 /proc/loadavg
load average取自/proc/loadavg。
9. 9. 8. 3/
前三个数字是1、5、分钟内进程队列中平均进程数,包括正在运行的进程+准备好等待运行的进程。
第四个数字分子表示正在运行的进程数,分母是进程总数。
最后一个数字是最近运行的进程ID号。
其中top取的是/proc/loadavg的前三个数。
1.2 top使用
打开top,可以指定更新的周期。
输入H,打开隐藏的线程;输入1,可以显示单核CPU使用情况。
top -H -b -d 1 -n > top.txt,每个1秒统计一次,共次,显示线程细节,并保存到top.txt中。
top采样来源你还依赖于/proc/stat和/proc//stat两个,这两个的详细介绍参考:/proc/stat和/proc//stat。
其中CPU信息对应的含义如下:
us是user的意思,统计nice小于等于0的用户空间进程,也即优先级为~。 ni是nice的意思,统计nice大于0的用户空间进程,也即优先级为~。 sys是system的意思,统计内核态运行时间,不包括中断。 id是idle的意思,几系统处于空闲态。 wa是iowait的意思,统计io等待时间。 hi是hardware interrupt,统计硬件中断时间。 si是software interrupt,统计软中断时间。 最后的st是steal的意思。
perf
通过sudo perf top -s comm,可以查看当前系统运行进程占比。
这里不像top一样区分idle、system、user,这里的占比是各个进程在总运行时间里面占比。
通过sudo perf record记录采样信息,然后通过sudo perf report -s comm。
sar、ksar
sar是System Activity Report的意思,可以用于实时观察当前系统活动,也可以生成历史记录的报告。
要使用sar需要安装sudo apt install sysstat,然后对sysstat进行配置。
sar用于记录统计信息,ksar用于将记录的信息图形化输出。
ksar下载地址在: github.com/vlsi/ksar/re...
sudo gedit /etc/default/sysstat--------------------------------将 ENABLED=“false“ 改为ENABLED=“true“。 sudo gedit /etc/cron.d/sysstat--------------------------------修改sar的周期等配置。 sudo /etc/init.d/sysstat restart--------------------------------重启sar服务 /var/log/sysstat/--------------------------------------------------sar log存放目录
使用sar记录开机到目前的统计信息到文件sar.txt。
LC_ALL=C sar -A > sar.txt
PS:这里直接使用sar -A,在ksar中无法正常显示。
如下执行java -jar ksar.jar,然后Data->Load from text file...选择保存的sar.txt文件。
得到如下的图表。
还可以通过sar记录一段时间的信息,指定采样周期和采样次数。
这些命令前加上LC_ALL=C之后保存到文件中,都可以在ksar中图形化显示。
collectl、colplot
collectl是一款非常优秀并且有着丰富的命令行功能的实用程序,你可以用它来采集描述当前系统状态的性能数据。
不同于大多数其它的系统监控工具,collectl 并非仅局限于有限的系统度量,相反,它可以收集许多不同类型系统资源的相关信息,如 cpu 、disk、memory 、network 、sockets 、 tcp 、inodes 、infiniband 、 lustre 、memory、nfs、processes、quadrics、slabs和buddyinfo等。
同时collectl还可以替代常用工具,比如top、vmstat、ps、iotop等。
安装collectl:
sudo apt-get install collectl
collectl的使用很简单,默认collectl显示cpu、磁盘、网络信息。
collectl还可以显示更多的子系统信息,如果选项存在对应的大写选项,大写选项表示更细节的设备统计信息。
b – buddy info (内存碎片) c – 所有CPU的合一统计信息;C - 单个CPU的统计信息。 d – 整个文件系统Disk合一统计信息;C - 单个磁盘的统计信息。 f – NFS V3 Data i – Inode and File System j – 显示每个CPU的Interrupts触发情况;J - 显示每个中断详细触发情况。 l – Lustre m – 显示整个系统Memory使用情况;M - 按node显示内存使用情况。 n – 显示整个系统的Networks使用情况;N - 分网卡显示网络使用情况。 s – Sockets t – TCP x – Interconnect y – 对系统所有Slabs (系统对象缓存)使用统计信息;Y - 每个slab使用的详细信息。
collectl --all显示所有子系统的统计信息,包括cpu、终端、内存、磁盘、网络、TCP、socket、文件系统、NFS。
collectl --top可以代替top命令:
collectl --vmstat可以代替vmstat命令:
collectl -c1 -sZ -i:1可以代替ps命令。
collectl和一些处理分析数据工具(比如colmux、colgui、colplot)结合能提供可视化图形。
colplot是collectl工具集的一部分,其将collectl收集的数据在浏览器中图形化展示。
colplot的介绍 在此,相关源码可以再 collectl-utils下载。
解压下载的colplot之后,sudo ./INSTALL安装colplot。
安装之后重启apache服务:
suod systemctl reload apache2 sudo systemctl restart apache2
在浏览器中输入 .0.0.1/colplot/,即可使用colplot。
通过Change Dir选择存放经过collectl -P保存的数据,然后设置Plot细节、显示那些子系统、plot大小等等。
最后Generate Plot查看结果。