当前位置: 首页 > 科技 > 文章内容页

新华三嵌入式一面:怎么理解Linux下的内存管理?

时间:2025-09-05    作者:游乐小编    

在物理内存管理上,Linux 采用分页机制,将内存划分为固定大小的页框,配合伙伴系统处理大块内存分配,避免碎片化;用 slab 分配器管理内核对象,提升小内存块的分配效率。

我理解的 Linux 内存管理,是系统内核对内存资源进行分配、回收、保护和优化的一套完整机制,其核心是在有限的物理内存资源下,为多进程提供高效、安全的内存使用环境。从用户视角看,每个进程都拥有独立的虚拟地址空间,这让进程无需关心物理内存的实际分布,简化了程序开发;而内核层面,通过内存管理单元(MMU)实现虚拟地址到物理地址的映射,既保证了进程间的内存隔离,又能通过地址转换实现内存共享。

在物理内存管理上,Linux 采用分页机制,将内存划分为固定大小的页框,配合伙伴系统处理大块内存分配,避免碎片化;用 slab 分配器管理内核对象,提升小内存块的分配效率。当内存紧张时,系统会基于 LRU 算法回收不常用页面,或通过 Swap 空间暂存数据,平衡供需。这套机制既解决了物理内存有限的问题,又通过隔离和保护机制保障了系统稳定,对嵌入式场景下的资源优化尤为关键。

Part1.Linux 内存管理

1.1物理内存与虚拟内存

物理内存(Physical Memory)是相对虚拟内存而言的,是指通过插在主板内存槽上的物理内存条而获得的内存空间。物理内存,即RAM(Random Access Memory,随机存取存储器),也叫主存(内存),是与 CPU 直接进行数据交互的内部存储器。它可以随时读写(刷新时除外),而且速度很快,主要作用是在计算机运行时为操作系统和各种程序提供临时储存。看计算机配置的时候,主要看的就是这个物理内存。

图片图片

虚拟内存(Virtual Memory,虚拟存储器)是计算机系统内存管理的一种技术,是指根据系统需要从硬盘匀出来的用来充当内存的那部分空间,主要用于辅助物理内存工作。虚拟内存在硬盘上以pagefile.sys(分页文件)存在,大小可以自定义,通常设置为物理内存的1-2倍左右。

(1)为何使用虚拟内存技术?

电脑中运行的所有程序,都需经过内存来执行,若执行的程序占用内存很大或很多,则会导致内存消耗殆尽。为了解决该问题,Windows 运用了虚拟内存技术,即匀出一部分硬盘空间来充当内存使用。若计算机运行程序或操作所需要的 RAM(随机存储器)不足时,则 Windows 会用这部分虚拟存储器进行补偿,以缓解内存的紧张。

(2)虚拟内存的工作流程?

虚拟存储器是由硬件和操作系统自动实现存储信息调度和管理的,包括6个步骤:

①中央处理器访问主存的逻辑地址分解成组号a和组内地址b,并对组号a进行地址变换,即将逻辑组号a作为索引,查地址变换表,以确定该组信息是否存放在主存内。②如该组号已在主存内,则转而执行④;如果该组号不在主存内,则检查主存中是否有空闲区,如果没有,便将某个暂时不用的组调出送往辅存,以便将这组信息调入主存。③从辅存读出所要的组,并送到主存空闲区,然后将那个空闲的物理组号a和逻辑组号a登录在地址变换表中。④从地址变换表读出与逻辑组号a对应的物理组号a。⑤从物理组号a和组内字节地址b得到物理地址。⑥根据物理地址从主存中存取必要的信息。

虚拟内存技术定义了一个连续的虚拟地址空间,并把内存扩展到硬盘空间。它使得应用程序认为自己拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。

交换空间(Swap Space)是虚拟内存的重要组成部分,它是磁盘上专门用于虚拟内存的区域。当物理内存不足时,Linux 内核会根据页面置换算法(如 LRU - 最近最少使用),将某些暂时不活跃的页面从物理内存移动到交换空间,为其他更需要内存的进程腾出空间。不过,由于磁盘 I/O 速度通常比内存访问速度慢得多,过度使用交换空间会导致系统性能下降,所以合理配置交换空间的大小非常重要。

一般来说,如果物理内存较小(比如小于 4GB),可以设置 swap 分区大小为内存的 2 倍;如果物理内存大于 4GB 而小于 16GB ,可以设置 swap 分区大小等于物理内存;如果内存大小在 16GB 以上,也可以设置 swap 为 0,但不建议这样做,因为一定大小的 swap 分区还是有作用的,比如在系统内存紧张时提供一定的缓冲。

1.2分页机制

分页是虚拟内存管理中的一种重要机制,它将内存空间划分为固定大小的块,这些块就被称为页(page) 。在 Linux 系统中,常见的页大小是 4KB(2^12 字节),不过在某些架构下,也支持如 64KB 或 2MB 的大页(Huge Pages) 。之所以采用固定大小的页,是为了简化内存管理和提高内存分配的效率。

图片图片

页表(Page Table)是分页机制的核心数据结构,它就像是一本 “地址字典”,记录了虚拟页与物理页之间的映射关系 。每个进程都拥有自己独立的页表,当进程访问内存时,CPU 会将虚拟地址发送给内存管理单元(MMU) ,MMU 通过查询页表,把虚拟地址转换为对应的物理地址。例如,在 x86_64 架构中,Linux 使用四级页表结构,分别为页全局目录(PGD)、页上级目录(PUD)、页中间目录(PMD)和页表项(PTE) 。

当 CPU 接收到一个虚拟地址时,首先会根据虚拟地址的最高几位在 PGD 中找到对应的 PUD;然后依据虚拟地址的次高几位在 PUD 中找到对应的 PMD;接着根据虚拟地址的再次高几位在 PMD 中找到对应的 PTE;最后,PTE 中记录了该虚拟页对应的物理页框地址,从而实现了虚拟地址到物理地址的转换。

以一个简单的例子来说明,假设我们有一个进程需要访问虚拟地址 0x12345678。在四级页表结构下,MMU 会先提取虚拟地址的高几位(比如高 9 位,具体位数根据架构和页表设计而定),通过这几位索引 PGD,找到对应的 PUD;再从虚拟地址中提取接下来的几位(同样根据设计而定),在 PUD 中找到对应的 PMD;然后继续提取相应位在 PMD 中找到 PTE;最终,PTE 中保存了物理页框地址,再结合虚拟地址中剩下的偏移部分,就可以得到实际的物理地址,进而访问到所需的数据 。

Part2.内存管理关键技术与组件

2.1内存管理单元(MMU)

内存管理单元(Memory Management Unit,MMU)是Linux内存管理中的关键硬件组件,就像是一位 “翻译官”,承担着虚拟地址与物理地址之间的转换工作。当应用程序运行时,它会产生虚拟地址,而MMU的任务就是将这些虚拟地址准确无误地映射到物理内存地址上,确保程序能够正确访问到所需的数据和指令 。

图片图片

MMU 主要通过页表(Page Table)来实现这种映射关系。页表是一个数据结构,它记录了虚拟页到物理页框的映射信息,每一个虚拟页在页表中都有对应的页表项(Page Table Entry,PTE),页表项中包含了物理页框号、访问权限、修改位等重要信息。当 MMU 接收到虚拟地址时,它会根据虚拟地址中的页号在页表中查找对应的页表项,从而获取到物理页框号,再结合虚拟地址中的页内偏移量,最终得到物理地址 。比如,当一个进程要访问虚拟地址 0x12345678 时,MMU 会从这个虚拟地址中提取出页号,假设为 0x123,然后在页表中查找页号为 0x123 的页表项,从该页表项中获取到对应的物理页框号,比如是 0x456,再将物理页框号与虚拟地址中的页内偏移量组合起来,得到最终的物理地址 0x4560000 + 0x345678 = 0x456345678,这样就完成了虚拟地址到物理地址的转换。

为了加快地址转换速度,MMU 还引入了快表(Translation Lookaside Buffer,TLB),也叫转换后备缓冲器。TLB 是一个高速缓存,它存储了最近使用过的页表项,当 MMU 进行地址转换时,会首先在 TLB 中查找,如果 TLB 中存在对应的页表项(即 TLB 命中),就可以直接从 TLB 中获取物理页框号,大大加快了地址转换速度,减少了内存访问时间 。

因为如果每次都要去内存中查找页表,由于内存访问速度相对较慢,会导致程序运行效率降低。而 TLB 的存在就像是在 MMU 和内存之间建立了一个快速通道,提高了地址转换的效率。只有在 TLB 中没有找到对应的页表项(即 TLB 未命中)时,MMU 才会去内存中的页表查找。例如,当一个进程频繁访问某个虚拟地址范围时,第一次访问时可能 TLB 未命中,需要去内存页表查找,但查找后会将对应的页表项存入 TLB,后续再次访问该虚拟地址时,就可以直接在 TLB 中命中,快速完成地址转换 。

MMU 除了地址转换功能外,还提供内存保护机制。它通过页表项中的访问权限位,如读权限、写权限和执行权限,来控制对内存的访问。当一个进程试图访问内存时,MMU 会检查该进程的访问权限是否与页表项中的权限一致,如果不一致,就会触发一个内存访问异常,操作系统会捕获这个异常并进行相应处理,比如终止违规进程,从而防止进程非法访问内存,保障系统的稳定性和安全性 。比如,一个进程试图写入一个只读的内存页面,MMU 检测到这种违规操作后,就会触发异常,操作系统会介入,避免进程对只读内存的非法修改,确保内存数据的完整性和系统的正常运行。

3.2伙伴系统(Buddy System)

伙伴系统是 Linux 内核用于管理物理内存的一种重要机制,它主要负责大内存块的分配和回收,就像一个聪明的仓库管理员,合理地管理着内存 “仓库” 中的资源 。其核心思想是将内存划分为大小为 2 的幂次方的块,比如 1 个页框、2 个页框、4 个页框、8 个页框等不同大小的内存块。这些不同大小的内存块被组织成 11 个块链表,每个链表中存储着相同大小的空闲内存块,这样当有内存分配请求时,伙伴系统可以快速找到合适大小的内存块进行分配 。

图片

当内核请求分配内存时,伙伴系统会从相应的块链表中查找与请求大小最匹配的空闲内存块。如果没有找到完全匹配的内存块,它会从更大的内存块链表中选择一个合适的内存块,然后将其分割成两个大小相等的 “伙伴” 内存块,其中一个用于满足当前的分配需求,另一个则作为空闲内存块保留在链表中,以备后续分配。例如,当一个进程请求分配 4 个页框大小的内存时,如果 4 个页框大小的块链表中没有空闲块,伙伴系统会从 8 个页框大小的块链表中选择一个空闲块,将其分割成两个 4 个页框大小的伙伴内存块,一个分配给进程,另一个则放入 4 个页框大小的块链表中 。

在内存回收阶段,当一个内存块被释放时,伙伴系统会检查其伙伴内存块是否也处于空闲状态。如果伙伴内存块是空闲的,就将这两个伙伴内存块合并成一个更大的内存块,并将其放入对应的更大块链表中。这个过程不断重复,直到无法合并为止 。比如,有两个相邻的 4 个页框大小的空闲内存块,它们是伙伴关系,当其中一个被释放后,伙伴系统检测到其伙伴也空闲,就会将它们合并成一个 8 个页框大小的内存块,然后将这个 8 个页框大小的内存块放入 8 个页框大小的块链表中。通过这种方式,伙伴系统可以有效地减少内存碎片的产生,提高内存利用率 。

伙伴系统的这种分配和回收策略,使得内存管理更加高效和有序。它能够快速响应内存分配请求,并且在内存回收时,尽可能地合并空闲内存块,避免了内存碎片化问题,为内核提供了稳定的内存资源支持,保证了系统中各种进程和任务的顺利运行 。

3.3 slab分配器

slab 分配器是 Linux 内核针对内核对象的内存管理机制,主要用于频繁分配和释放小内存块的场景,它就像是一个专门为小内存块服务的 “快速补给站” 。在 Linux 内核中,有许多内核对象,如进程描述符、文件描述符、inode 节点等,这些对象的大小通常比较小,而且它们的创建和销毁非常频繁,如果使用伙伴系统来分配和回收这些小内存块,会因为伙伴系统以页为单位分配内存,粒度较大,容易产生大量的内部碎片,造成内存浪费 。

图片图片

slab 分配器通过维护多个不同大小的对象缓存来解决这个问题。对于每一种特定类型和大小的内核对象,slab 分配器都会创建一个对应的缓存(Cache),每个缓存中包含了多个相同大小的内存块,这些内存块被称为对象(Object) 。当内核需要分配一个对象时,slab 分配器会首先检查对应的缓存中是否有空闲对象,如果有,就直接从缓存中取出一个空闲对象返回给内核,避免了从伙伴系统中重新分配内存的开销;当对象不再使用时,它会被放回对应的缓存中,而不是释放回伙伴系统,以便下次分配时可以快速复用 。例如,对于进程描述符(task_struct),slab 分配器会创建一个专门的缓存,当需要创建一个新的进程时,就可以直接从这个缓存中获取一个空闲的进程描述符对象,而不需要重新向伙伴系统申请内存;当进程结束时,对应的进程描述符对象会被放回缓存,等待下一次使用 。

slab 分配器还引入了 slab 的概念,一个 slab 是由一个或多个连续的物理页组成,它被划分为一系列等大小的对象槽位,用于存放对象 。slab 有三种状态:空闲(free)、部分使用(partial)和满载(full) 。当一个 slab 中的所有对象都空闲时,它处于空闲状态;当 slab 中有部分对象被分配出去时,它处于部分使用状态;当 slab 中的所有对象都被分配时,它处于满载状态 。slab 分配器会根据对象的分配和释放情况,动态调整 slab 的状态,并且会尽量保持一定数量的空闲 slab,以便快速响应新的内存分配请求 。

slab分配器通过这种缓存机制和对象管理方式,大大提高了小内存块的分配和回收效率,减少了内存碎片的产生,同时还可以对内核对象进行预初始化,进一步提高了系统性能,是 Linux 内核内存管理中不可或缺的一部分 。

Part3.内存分配与回收机制

3.1内存分配流程

在 Linux 系统中,内存分配根据所处的运行环境分为用户态和内核态两种情况,各自有着不同的分配过程和系统调用。

用户态下,当我们编写 C 语言程序时,经常会用到malloc函数来分配内存 。malloc函数是 C 标准库提供的内存分配函数,它并非直接与内核交互,而是在用户空间内管理内存。malloc的底层实现依赖于操作系统提供的系统调用,主要涉及brk和mmap 。当程序调用malloc请求分配内存时,malloc首先会检查其维护的内存池(堆内存)中是否有足够大小的空闲内存块 。

如果有,就直接从内存池中分配一块合适的内存返回给程序;如果内存池中没有足够的空闲内存,malloc会根据请求内存的大小来决定下一步操作 。如果请求的内存较小,它会尝试通过brk系统调用扩展堆内存(即移动break指针,break指针指向堆空间的某个地址,从堆起始地址到break之间的地址空间为映射好的,可以供进程访问 ),然后从新扩展的堆内存中分配内存块给程序 。

例如,一个程序调用malloc(1024)请求分配 1024 字节的内存,malloc在检查内存池后发现空间不足,就可能通过brk扩展堆内存,然后从新扩展的区域中划出 1024 字节返回给程序 。如果请求的内存较大(通常大于 128KB,这个阈值在不同系统中可能会有所不同),malloc会使用mmap系统调用直接向内核申请一块独立的内存映射区域,将文件或者设备映射到进程的地址空间,这块内存区域独立于堆内存,并且在使用完毕后可以直接通过munmap系统调用释放,而不会与堆内存产生关联 。比如,当一个程序需要加载一个较大的共享库文件时,就可能通过mmap将共享库文件映射到进程地址空间,方便程序对其进行访问 。

内核态下的内存分配则更为复杂和关键,因为内核负责管理整个系统的内存资源,为各种内核对象和进程提供内存支持 。内核主要通过伙伴系统和 slab 分配器来进行内存分配 。当内核需要分配大块内存(通常以页为单位,一页大小一般为 4KB 或 8KB)时,会使用伙伴系统 。伙伴系统将物理内存划分为大小为 2 的幂次方的块,这些不同大小的内存块被组织成 11 个块链表 。当内核请求分配内存时,伙伴系统会从相应的块链表中查找与请求大小最匹配的空闲内存块 。如果没有找到完全匹配的内存块,它会从更大的内存块链表中选择一个合适的内存块,然后将其分割成两个大小相等的 “伙伴” 内存块,其中一个用于满足当前的分配需求,另一个则作为空闲内存块保留在链表中 。

例如,内核请求分配 8 个页框大小的内存,如果 8 个页框大小的块链表中没有空闲块,伙伴系统会从 16 个页框大小的块链表中选择一个空闲块,将其分割成两个 8 个页框大小的伙伴内存块,一个分配给内核,另一个放入 8 个页框大小的块链表 。对于频繁分配和释放的小内存块,内核使用 slab 分配器 。slab 分配器针对每一种特定类型和大小的内核对象,维护了多个不同大小的对象缓存 。

当内核需要分配一个对象时,slab 分配器会首先检查对应的缓存中是否有空闲对象,如果有,就直接从缓存中取出一个空闲对象返回给内核;当对象不再使用时,它会被放回对应的缓存中,而不是释放回伙伴系统,以便下次分配时可以快速复用 。比如,对于进程描述符(task_struct),slab 分配器会创建一个专门的缓存,当需要创建一个新的进程时,就可以直接从这个缓存中获取一个空闲的进程描述符对象 。

3.2内存回收策略

Linux 系统采用了多种内存回收策略来确保系统内存的高效利用和稳定运行,其中 “最近最少使用(LRU)” 算法是内存回收的核心算法之一 。Linux 内核维护了两个双向链表,分别是活跃内存页链表(active_list)和不活跃内存页链表(inactive_list) 。active_list中存放的是进程经常访问的内存页,这些内存页被认为是活跃的,在内存回收时一般不会被淘汰 ;而inactive_list中则是进程很少访问的内存页,这些不活跃的内存页是内存回收的主要目标 。

每个内存页都有一个PG_referenced标志位,表示此内存页是否被访问过,这个标志位在内存回收过程中起着至关重要的作用 。当某个进程申请一个匿名内存页时,内核会把这个内存页添加到active_list中,并且将PG_referenced标志位设置为 0 。如果内存页原来处于active_list中,再次被访问时,会把此内存页的PG_referenced设置为 1 。当某个处于inactive_list链表中且PG_referenced为 0 的内存页被访问时,也会将其PG_referenced值变为 1 ;当某个处于inactive_list链表中且PG_referenced为 1 的内存页被访问时,会将此内存页移动到active_list,并且将PG_referenced置为 0 。

当系统内存不足时,内核会从inactive_list的尾部开始进行内存淘汰 。如果内存页的PG_referenced标志位为 1,说明该内存页最近被访问过,将跳过此内存页,并且将此内存页的PG_referenced标志位设置为 0 ;如果内存页的PG_referenced标志位为 0,那么将此内存页写入到磁盘当中(如果是匿名内存页,会写入到交换分区;如果是与文件映射的内存页,会写回到文件),并且将所有与此内存页的映射解除绑定,然后释放此内存页 。在淘汰的过程中,active_list链表中的内存页也要进行衰退,扫描active_list链表,当其PG_referenced值为 1 时将其置为 0,当值为 0 时,要将其从active_list链表移到inactive_list链表中 ,这样可以保证active_list中始终是最活跃的内存页 。

除了基于LRU算法的内存回收,Linux还会在特定情况下进行页面交换操作,也就是将内存中的数据交换到磁盘的交换空间(Swap Space) 。当系统内存紧张,可用内存不足时,内核会触发swap机制 。对于匿名内存页(如进程的堆、栈、数据段等没有与文件映射的内存页),如果系统设置了交换分区或交换文件,内核会将这些匿名内存页写入到交换分区中,释放出物理内存供其他更需要的进程使用 。

而对于与文件有映射关系的内存页(如代码段、mmap 段等),只需要将数据写回到文件即可(代码段内容一般不会改变,所以不用回写) 。例如,当一个占用大量内存的程序在运行时,系统内存逐渐紧张,内核可能会将该程序中一些不常用的匿名内存页交换到交换分区,释放出物理内存给其他进程使用 。当该程序后续需要再次访问这些被交换出去的内存页时,会产生缺页异常,内核会从交换分区中将相应的内存页读取回物理内存 。

内核通过 kswapd 内核线程来进行内存回收的监控和处理 。kswapd 线程会定期检查系统内存的使用情况,当剩余内存慢慢减少,触碰到 low 水位时,就会触发 kswapd 线程的内存回收工作 。它会根据 LRU 算法对不活跃的内存页进行回收,将其写入磁盘或交换分区,释放物理内存 。如果在回收过程中,内存慢慢增加,触碰到 high 水位时,就会停止回收 。每个内存区域(zone)都有自己的 low、min 和 high 水位,并且 kswapd 线程是针对所在 node(节点)进行内存回收的,只会对分配了一定数量页框后空闲页框数量小于此 zone 的 high 阀值加上保留页框数量的 zone 进行内存回收 。

此外,用户也可以通过修改/proc/sys/vm/swapness参数来控制内存回收时对匿名页和文件缓存页的回收倾向 。swapness的值表示系统将内存页交换到磁盘交换空间的倾向程度,取值范围是0 - 100 。当swapness值较大时,系统会更积极地回收匿名页,将其交换到交换空间;当值较小时,系统则更倾向于回收文件缓存页 。例如,将 swapness设置为10,表示系统在内存回收时,只有当内存非常紧张时才会较多地使用交换空间来回收匿名页 。

Part4.监控与优化内存使用

4.1监控工具使用

在 Linux 系统中,有许多实用的工具可以帮助我们监控内存使用情况,及时发现潜在问题。

free命令是最常用的内存监控命令之一,它能快速展示系统内存的使用概况 。使用free -h命令(-h参数表示以人类可读的格式显示),会输出类似这样的信息:

total used free shared buff/cache availableMem: 7.8Gi 317Mi 6.0Gi 1.0Mi 1.4Gi 7.2GiSwap: 4.0Gi 0B 4.0Gi

其中,total表示系统内存总量;used是已使用的内存量;free为空闲内存量;shared是被多个进程共享的内存量;buff/cache是用于文件系统缓存和缓冲区的内存量;available则是在不影响系统性能的情况下可分配给新进程的大约内存量 。通过观察这些数据,我们能直观了解系统内存的整体使用状态,比如当used接近total时,可能意味着系统内存不足 。

top命令提供了实时的系统监控视图,不仅能查看内存使用情况,还能展示 CPU、进程等信息 。在终端输入top命令后,会看到一个动态更新的界面,按下Shift + M可以按照内存使用量对进程进行排序,方便找出占用内存较多的进程 。例如,当系统运行缓慢时,通过top查看内存占用大户,可能会发现某个进程占用了大量内存,这就需要进一步排查该进程是否存在内存泄漏或不合理的内存使用情况 。在top命令的输出中,VIRT表示进程使用的虚拟内存总量;RES是进程使用的、未被换出的物理内存大小;SHR为共享内存大小 。计算一个进程实际使用的内存可以用RES - SHR 。通过这些指标,我们能深入分析每个进程的内存使用细节 。

vmstat命令可以展现给定时间间隔的服务器的状态值,包括 CPU 使用率、内存使用率、虚拟内存交换情况、I/O 读写情况等 。使用vmstat 2(表示每 2 秒采集一次数据)命令,会得到如下输出示例:

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----r b swpd free buff cache si so bi bo in cs us sy id wa st1 0 0 4777576 153688 1299500 0 0 0 1500 2098 0 0 98 0 0

其中,swpd表示使用的虚拟内存大小;free是可用的物理内存大小;si为每秒从交换分区读入到 RAM 的大小;so是每秒从 RAM 写出到交换分区的大小 。如果swpd大于 0 且si、so的值长期不为 0,说明系统在频繁进行内存和交换空间的数据交换,可能存在内存不足的问题,会影响系统性能 。

除了这些命令行工具,我们还可以通过/proc/meminfo文件获取内存信息 。这是一个动态更新的虚拟文件,包含了丰富的内存使用情况报告 。使用cat /proc/meminfo命令查看,会输出类似下面的内容:

MemTotal: 3855952 kBMemFree: 2040864 kBMemAvailable: 3356504 kBBuffers: 39224 kBCached: 1400764 kBSwapCached: 0 kBActive: 86028 kBInactive: 1536020 kBActive(anon): 244 kBInactive(anon): 182156 kBActive(file): 85784 kBInactive(file): 1353864 kBUnevictable: 0 kBMlocked: 0 kBSwapTotal: 0 kBSwapFree: 0 kBDirty: 96 kBWriteback: 0 kBAnonPages: 179504 kBMapped: 215608 kBShmem: 336 kBKReclaimable: 123612 kBSlab: 148076 kBSReclaimable: 123612 kBSUnreclaim: 24464 kBKernelStack: 2912 kBPageTables: 2984 kBNFS_Unstable: 0 kBBounce: 0 kBWritebackTmp: 0 kBCommitLimit: 1927976 kBCommitted_AS: 482236 kBVmallocTotal: 34359738367 kBVmallocUsed: 16208 kBVmallocChunk: 0 kBPercpu: 1016 kBHardwareCorrupted: 0 kBAnonHugePages: 104448 kBShmemHugePages: 0 kBShmemPmdMapped: 0 kBFileHugePages: 0 kBFilePmdMapped: 0 kB

这个文件中的各项数据详细记录了系统内存的各个方面,如总内存(MemTotal)、空闲内存(MemFree)、可用内存(MemAvailable)、缓冲区(Buffers)、缓存(Cached)等 。它是许多内存监控工具的数据源,通过直接分析这个文件,我们可以获取更全面和深入的内存信息 。例如,MemAvailable是内核使用特定算法估算出来的可分配给应用程序的内存数量,它比MemFree更能反映系统实际可用的内存情况 。当我们在排查内存问题时,/proc/meminfo中的数据能为我们提供重要的参考依据 。

4.2优化策略

当我们通过监控工具发现系统内存使用存在问题时,就需要采取相应的优化策略来提升系统性能。

调整交换空间大小是一种常见的优化手段。如果系统内存不足,合理增加交换空间可以缓解内存压力。比如在安装系统时,默认分配的交换空间较小,随着系统使用和应用程序的增加,可能需要扩大交换空间 。可以通过添加 swap 分区或创建 swap 文件的方式来实现 。首先,使用fdisk或parted工具查看磁盘分区情况,确定哪些分区可以用于创建 swap 分区 。假设要在一块新磁盘上创建 swap 分区,使用fdisk工具对新磁盘进行分区操作,创建一个新分区并将其标记为 swap 类型 。

然后,使用mkswap命令格式化新的 swap 分区,例如mkswap /dev/sda3(假设新分区为/dev/sda3) 。最后,使用swapon命令启用新的 swap 分区,即swapon /dev/sda3 。如果不想使用新磁盘分区,也可以创建 swap 文件 。使用dd命令创建一个指定大小的文件,如dd if=/dev/zero of=/swapfile bs=1M count=2048表示创建一个大小为 2GB 的 swap 文件 。

接着,使用mkswap命令将其格式化为 swap 文件,mkswap /swapfile 。最后,使用swapon命令启用 swap 文件,swapon /swapfile 。在调整交换空间大小时,要注意确保系统中的 swap 空间大小能够满足系统运行的需求,但也不能设置过大,因为过度使用交换空间会导致系统性能下降,一般建议根据物理内存大小来合理设置 swap 空间大小 。

优化应用程序的内存使用是提高系统性能的关键。从程序设计角度来看,要避免内存泄漏问题 。在 C 语言中,使用malloc分配内存后,一定要记得使用free释放内存,否则会导致内存泄漏 。例如:

#include #include int main() { int *ptr = (int *)malloc(10 * sizeof(int)); if (ptr == NULL) { printf("内存分配失败 "); return 1; } // 使用ptr // 这里忘记释放ptr所指向的内存,会导致内存泄漏 return 0;}

在上述代码中,如果忘记在程序结束前调用free(ptr)释放内存,随着程序多次运行,会不断占用内存,最终导致系统内存不足 。对于大型项目,可以使用内存检测工具如valgrind来检测内存泄漏和其他内存错误 。在 Java 中,要注意对象的生命周期管理,及时释放不再使用的对象,避免对象长时间占用内存 。例如,当一个对象不再被使用时,应将其引用设置为null,以便垃圾回收器(GC)能够及时回收其占用的内存 。

此外,还可以通过调整 Java 虚拟机(JVM)的参数来优化内存使用,如设置堆内存的大小 。可以使用-Xms和-Xmx参数来分别设置 JVM 初始堆大小和最大堆大小 。例如,java -Xms512m -Xmx1024m MyApp表示设置 JVM 初始堆大小为 512MB,最大堆大小为 1024MB 。合理设置这些参数可以避免 JVM 频繁进行垃圾回收,提高程序的性能 。

除了上述方法,还可以通过优化系统配置来提高内存使用效率。比如调整/proc/sys/vm/swappiness参数,它表示系统将内存页交换到磁盘交换空间的倾向程度,取值范围是 0 - 100 。当swappiness值较大时,系统会更积极地回收匿名页,将其交换到交换空间;当值较小时,系统则更倾向于回收文件缓存页 。如果系统内存充足,可以将swappiness设置为较小的值,如 10,减少不必要的内存交换操作,提高系统性能 。可以通过编辑/etc/sysctl.conf文件,添加或修改vm.swappiness = 10,然后执行sysctl -p使配置生效 。

热门推荐

更多

热门文章

更多

首页  返回顶部

本站所有软件都由网友上传,如有侵犯您的版权,请发邮件youleyoucom@outlook.com