linux内存管理机制,内存管理机制

大家好,感谢邀请,今天来为大家分享一下linux内存管理机制的问题,以及和内存管理机制的一些困惑,大家要是还不太明白的话,也没有关系,因为接下来将为大家分享,希望可以帮助到大家,解决大家的问题,下面就开始吧!

Linux 内核的内存管理 - 概念

Concepts overview— The Linux Kernel documentation

Linux中的内存管理是一个复杂的系统,经过多年的发展,它包含越来越多的功能,以支持从 MMU-less microcontrollers到 supercomputers的各种系统。

没有MMU内存管理的系统被称为 nommu,它值得写一份专门的文档进行描述。

尽管有些概念是相同的,这里我们假设MMU可用,CPU可以将虚拟地址转换为物理地址。

计算机系统中的物理内存是有限资源,即便支持内存热插拔,其可以安装的内存也有限的。物理内存不一定必须是连续的;它可以作为一组不同的地址范围被访问。此外,不同的CPU架构,甚至同架构的不同实现对如何定义这些地址范围都是不同的。

这使得直接处理物理内存异常复杂,为了避免这种复杂性,开发了虚拟内存(virtual memory)的概念。

虚拟内存从应用软件中抽象出物理内存的细节,只允许在物理内存中保留需要的信息(demand paging),并提供一种机制来保护和控制进程之间的数据共享。

通过虚拟内存,每次内存访问都访问一个虚拟地址。当CPU对从系统内存读取(或写入)的指令进行解码时,它将该指令中编码的虚拟地址转换为内存控制器可以理解的物理地址。

物理内存被切分为页帧 page frames或页 pages。页的大小是基于架构的。一些架构允许从几个支持的值中选择页大小;此选择在内核编译时设置到内核配置。

每个物理内存页都可以映射为一个或多个虚拟页(virtual pages)。映射关系描述在页表(page tables)中,页表将程序使用的虚拟地址转换为物理内存地址。页表以层次结构组织。

最底层的表包含软件使用的实际内存页的物理地址。较高层的表包含较低层表页的物理地址。顶层表的指针驻留在寄存器中。

当CPU进行地址转换的时候,它使用寄存器访问顶级页表。

虚拟地址的高位,用于顶级页表的条目索引。然后,通过该条目访问下级,下级的虚拟地址位又作为其下下级页表的索引。虚拟地址的最低位定义实际页内的偏移量。

地址转换需要多次内存访问,而内存访问相对于CPU速度来说比较慢。为了避免在地址转换上花费宝贵的处理器周期,CPU维护着一个称为 TLB(Translation Lookaside Buffer)的用于地址转换缓存(cache)。通常TLB是非常稀缺的资源,需要大内存工作应用程序会因为TLB未命中而影响性能。

很多现代CPU架构允许页表的高层直接映射到内存页。例如,x86架构,可以通过二级、三级页表的条目映射2M甚至1G内存页。在Linux中,这些内存页称为大页(Huge)。大页的使用显著降低了TLB的压力,提高了TLB命中率,从而提高了系统的整体性能。

Linux提供两种机制开启使用大页映射物理内存。

第一个是 HugeTLB文件系统,即 hugetlbfs。它是一个伪文件系统,使用RAM作为其存储。在此文件系统中创建的文件,数据驻留在内存中,并使用大页进行映射。

关于 HugeTLB Pages

另一个被称为 THP(Transparent HugePages),后出的开启大页映射物理内存的机制。

与 hugetlbfs不同,hugetlbfs要求用户和/或系统管理员配置系统内存的哪些部分应该并可以被大页映射;THP透明地管理这些映射并获取名称。

关于 Transparent Hugepage Support

通常,硬件对不同物理内存范围的访问方式有所限制。某些情况下,设备不能对所有可寻址内存执行DMA。在其他情况下,物理内存的大小超过虚拟内存的最大可寻址大小,需要采取特殊措施来访问部分内存。还有些情况,物理内存的尺寸超过了虚拟内存的最大可寻址尺寸,需要采取特殊措施来访问部分内存。

Linux根据内存页的使用情况,将其组合为多个 zones。比如, ZONE_DMA包含设备用于DMA的内存, ZONE_HIGHMEM包含未永久映射到内核地址空间的内存, ZONE_NORMAL包含正常寻址内存页。

内存zones的实际层次架构取决于硬件,因为并非所有架构都定义了所有的zones,不同平台对DMA的要求也不同。

多处理器机器很多基于 NUMA(Non-Uniform Memory Access system-非统一内存访问系统)架构。在这样的系统中,根据与处理器的“距离”,内存被安排成具有不同访问延迟的 banks。每个 bank被称为一个 node,Linux为每个 node构造一个独立的内存管理子系统。 Node有自己的zones集合、free&used页面列表,以及各种统计计数器。

What is NUMA?

NUMA Memory Policy

物理内存易失,将数据放入内存的常见情况是读取文件。读取文件时,数据会放入页面缓存(page cache),可以在再次读取时避免耗时的磁盘访问。同样,写文件时,数据也会被放入页面缓存,并最终进入存储设备。被写入的页被标记为脏页(dirty page),当Linux决定将其重用时,它会将更新的数据同步到设备上的文件。

匿名内存 anonymous memory或匿名映射 anonymous mappings表示没有后置文件系统的内存。这些映射是为程序的stack和heap隐式创建的,或调用mmap(2)显式创建的。通常,匿名映射只定义允许程序访问的虚拟内存区域。读,会创建一个页表条目,该条目引用一个填充有零的特殊物理页。写,则分配一个常规物理页来保存写入数据。该页将被标记为脏页,如果内核决定重用该页,则脏页将被交换出去 swapped out。

纵贯整个系统生命周期,物理页可用于存储不同类型的数据。它可以是内核内部数据结构、设备驱动DMA缓冲区、读取自文件系统的数据、用户空间进程分配的内存等。

根据内存页使用情况,Linux内存管理会区别处理。可以随时释放的页面称为可回收(reclaimable)页面,因为它们把数据缓存到了其他地方(比如,硬盘),或者被swap out到硬盘上。

可回收页最值得注意的是页面缓存和匿名页面。

在大多数情况下,存放内部内核数据的页,和用作DMA缓冲区的页无法重用,它们将保持现状直到用户释放。这样的被称为不可回收页(unreclaimable)。

然而,在特定情况下,即便是内核数据结构占用的页面也会被回收。

例如,文件系统元数据的缓存(in-memory)可以从存储设备中重新读取,因此,当系统存在内存压力时,可以从主内存中丢弃它们。

释放可回收物理内存页并重新调整其用途的过程称为(surprise!) reclaim。

Linux支持异步或同步回收页,取决于系统的状态。

当系统负载不高时,大部分内存是空闲的,可以立即从空闲页得到分配。

当系统负载提升后,空闲页减少,当达到某个阈值( low watermark)时,内存分配请求将唤醒 kswapd守护进程。它将以异步的方式扫描内存页。如果内存页中的数据在其他地方也有,则释放这些内存页;或者退出内存到后置存储设备(关联脏页)。

随着内存使用量进一步增加,并达到另一个阈值- min watermark-将触发回收。这种情况下,分配将暂停,直到回收到足够的内存页。

当系统运行时,任务分配并释放内存,内存变得碎片化。

虽然使用虚拟内存可以将分散的物理页表示为虚拟连续范围,但有时需要分配大的连续的物理内存。这种需求可能会提升。例如,当设备驱动需要一个大的DMA缓冲区时,或当THP分配一个大页时。

内存地址压缩(compaction)解决了碎片问题。

该机制将占用的页从内存zone的下部移动到上部的空闲页。压缩扫描完成后,zone开始处的空闲页就并在一起了,分配较大的连续物理内存就可行了。

与 reclaim类似, compaction可以在 kcompactd守护进程中异步进行,也可以作为内存分配请求的结果同步进行。

在存在负载的机器上,内存可能会耗尽,内核无法回收到足够的内存以继续运行。

为了保障系统的其余部分,引入了 OOM killer。

OOM killer选择牺牲一个任务来保障系统的总体健康。选定的任务被killed,以期望在它退出后释放足够的内存以继续正常的操作。

内存管理:一文读懂Linux内存组织结构及页面布局

1、内存是什么?

1)内存又称主存,是 CPU能直接寻址的存储空间,由半导体器件制成;

2)内存的特点是存取速率快,断电一般不保存数据,非持久化设备;

2、内存的作用

1)暂时存放 cpu的运算数据

2)硬盘等外部存储器交换的数据

3)保障 cpu计算机的稳定性和高性能

1、linux内存地址空间 Linux内存管理全貌

2、内存地址——用户态&内核态

3、内存地址——MMU地址转换

4、内存地址——分段机制

1)段选择符

更多Linux内核视频教程文档资料免费领取后台私信【内核】自行获取。

内核学习网站:

Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈-学习视频教程-腾讯课堂

2)分段实现

5、内存地址——分页机制(32位)

6、用户态地址空间

7、内核态地址空间

8、进程内存空间

内存管理算法——对讨厌自己管理内存的人来说是天赐的礼物

1、内存碎片

1)基本原理

2)如何避免内存碎片

2、伙伴系统算法——组织结构

1)概念

2)外部碎片

3、伙伴系统算法——申请和回收

1)申请算法

2)回收算法

3)条件

4、如何分配 4M以上内存?

1)为何限制大块内存分配

2)内核中获取 4M以上大内存的方法

5、伙伴系统——反碎片机制

1)不可移动页

2)可回收页

6、slab算法——基本原理

1)基本概念

2)内部碎片

7、slab分配器的结构

详细参考:

经典|图解Linux内存性能优化核心思想

8、slab高速缓存

1)普通高速缓存

2)专用高速缓存

9、内核态内存池

1)基本原理

2)内核 API

10、用户态内存池

1) C++实例

11、DMA内存

1)什么是 DMA

2) DMA信号

out of memory的时代过去了吗?no,内存再充足也不可任性使用。

1、内存的使用场景

2、用户态内存分配函数

a)如果当前连续内存块足够 realloc的话,只是将 p所指向的空间扩大,并返回 p的指针地址。这个时候 q和 p指向的地址是一样的

b)如果当前连续内存块不够长度,再找一个足够长的地方,分配一块新的内存,q,并将 p指向的内容 copy到 q,返回 q。并将 p所指向的内存空间删除

3、内核态内存分配函数

4、malloc申请内存

5、缺页异常

6、用户进程访问内存分析

7、共享内存

1)原理

2) shm接口

1、C内存泄露

2、C野指针

3、C资源访问冲突

4、STL迭代器失效

错误示例:删除当前迭代器,迭代器会失效

正确示例:迭代器 erase时,需保存下一个迭代器

5、C++ 11智能指针

(1)原理分析:

(2)数据结构:

(3)使用方法:

6、C++ 11更小更快更安全

六、如何查看内存

可以通过 cat/proc/slabinfo命令查看

可以通过/proc/sys/vm/drop_caches来释放

Linux内核:内存管理——CMA机制

Linux内核中的CMA(连续内存区管理)机制是为了提供连续物理内存块,以满足某些特定设备和应用的需求。CMA机制的实现,主要是为了解决在嵌入式设备中,如摄像头、硬件视频解码器和编码器等设备的内存需求问题。这些设备往往需要较大的内存缓冲区,并且对内存的连续性和特定边界对齐有严格要求。CMA机制通过专门管理一块连续的物理内存区域,确保了设备在工作时能获得所需的连续内存资源,同时在不使用时,这部分内存可以被其他模块高效地利用。

在传统的Linux内核中,通过预留内存区域的方式来满足大块连续内存需求,但这种方式会导致一部分内存被固定占用,无法灵活地分配给其他模块使用。CMA机制的引入,使得系统能够动态地管理和分配这块连续的物理内存,使得它既可以满足特定设备在运行时的连续内存需求,又能在这些设备不工作时释放这部分内存,供其他模块申请使用,从而提高了内存的利用率和系统的整体效率。

在数据传输方向涉及DMA(直接内存访问)时,尤其是设备不支持scatter-gather形式的DMA或CPU不具备使用虚拟地址作为目标地址的IOMMU/SMMU机制时,连续的物理内存成为了必需。CMA机制在这种场景下显得尤为重要,因为它能够提供满足这些特殊需求的连续内存资源。

CMA区域的内存管理通过struct cma结构体进行,其中包含了起始物理页面地址、内存页面数量以及内存状态的位图标记等信息。CMA内存分配和释放接口与传统的DMA接口相集成,使得系统在调用CMA接口时,能够自动管理这块连续内存的分配和释放过程,实现内存资源的高效利用。

通过CMA机制,Linux内核能够在保证特定应用和设备需求的同时,最大化地提高系统的内存使用效率,这对于嵌入式设备和对内存管理有严格要求的应用场景尤为重要。

阅读剩余
THE END