linux内存机制?linux内核内存管理

今天给各位分享linux内存机制的知识,其中也会对linux内核内存管理进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

linux内核调试(九)内核内存检测机制介绍

内存检测机制是内核中用于识别和定位内存相关问题的重要工具。在c语言编程中,内存问题是出现概率最高且最难定位的问题之一。由于内核线性映射区中连续的物理地址会被映射到连续的虚拟地址,内存越界写操作很难被及时发现。例如,当某个模块通过kmalloc分配内存后,执行写操作越界时,可能会篡改另一个模块的数据,导致系统异常或模块功能异常,但此时系统并不会检测到这一情况。内存检测机制正是为了解决这类问题而设计的。

内核提供了多种内存检测机制,如slub_debug、kasan、kfence、vmalloc的guard page、栈的canary保护、以及kmemleak等。它们各有特点,但主要功能都是为了检测内存访问越界、访问释放后的内存、重复释放内存等问题。下面将分别介绍它们的使用方式。

slub debug是一种内存检测工具,主要通过redzone和内存poison的方式实现对内存问题的检测。打开内核选项并添加命令行选项“slub_debug=UFPZ”以启用检测功能。该选项包含以下功能:

U:跟踪slab内存的属性,如创建时所属的CPU、进程、时间。

F:开启sanity检查功能,检测slab操作中是否有非法内存访问。

P:开启poisoning功能,检测释放后的内存访问。

Z:开启redzoning功能,检测内存越界访问。

在slab内存非法操作时,需要手动通过sysfs的validate属性触发检测操作。若要检测特定大小的kmalloc对象,可使用命令执行检测。

slub debug的优点在于能够检测slab内存问题,但缺点是只能检测slab内存,无法检测全局变量、栈等问题,且不能立即检测内存非法访问,需要依赖手动触发。

kasan是内核中另一种全面的内存检测工具,通过编译时插桩实现对内存问题的即时检测,能够检测包括slab内存、栈、全局变量和vmlloc内存问题。为了支持kasan,gcc版本需要高于8.03。kasan的优点是检测范围广,但会带来资源开销和性能损失,因此通常用于开发阶段或产品发布前的测试,而非实际生产环境。

kfence是内核中引入的一种低开销内存检测机制,通过维护内存池并抽样检测实现内存问题的检测。kfence内存池中的每个page都包含一个guard page,抽样检测内存访问。配置选项包括样本周期和对象数量。kfence的优点是资源消耗小,适用于生产环境,但使用抽样检测机制,检测结果可能不够精确。

kmemleak主要用于检测内存泄漏问题,通过跟踪内存分配接口并维护红黑树记录未释放内存。系统会周期性地执行扫描操作,或通过debugfs手动触发。kmemleak的优点是能够检测到大部分内存泄漏问题,但可能无法检测到特定情况下的内存泄漏,且性能影响较大,不适合生产环境使用。

内存检测机制是内核中不可或缺的组件,通过它们,开发人员可以更有效地定位和解决问题,提高系统的稳定性和安全性。每个机制都有其适用场景和限制,合理选择和配置是关键。

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操作系统中内存buffer和cache的区别

更详细的解释参考:Difference Between Buffer and Cache

对于共享内存(Shared memory),主要用于在UNIX环境下不同进程之间共享数据,是进程间通信的一种方法,一般的应用程序不会申请使用共享内存,笔者也没有去验证共享内存对上面等式的影响。如果你有兴趣,请参考:What is Shared Memory?

cache和 buffer的区别:

Cache:高速缓存,是位于CPU与主内存间的一种容量较小但速度很高的存储器。由于CPU的速度远高于主内存,CPU直接从内存中存取数据要等待一定时间周期,Cache中保存着CPU刚用过或循环使用的一部分数据,当CPU再次使用该部分数据时可从Cache中直接调用,这样就减少了CPU的等待时间,提高了系统的效率。Cache又分为一级Cache(L1 Cache)和二级Cache(L2 Cache),L1 Cache集成在CPU内部,L2 Cache早期一般是焊在主板上,现在也都集成在CPU内部,常见的容量有256KB或512KB L2 Cache。

Buffer:缓冲区,一个用于存储速度不同步的设备或优先级不同的设备之间传输数据的区域。通过缓冲区,可以使进程之间的相互等待变少,从而使从速度慢的设备读入数据时,速度快的设备的操作进程不发生间断。

Free中的buffer和cache:(它们都是占用内存):

buffer:作为buffer cache的内存,是块设备的读写缓冲区

cache:作为page cache的内存,文件系统的cache

如果 cache的值很大,说明cache住的文件数很多。如果频繁访问到的文件都能被cache住,那么磁盘的读IO bi会非常小。

==============================================================================================

cache是高速缓存,用于CPU和内存之间的缓冲;

buffer是I/O缓存,用于内存和硬盘的缓冲

cache最初用于cpu cache,主要原因是cpu与memory,由于cpu快,memory跟不上,且有些值使用次数多,所以放入

cache中,主要目的是,重复使用,并且一级\二级物理cache速度快,

buffer主要用于disk与 memory,主要是保护硬盘或减少网络传输的次数(内存数据表现dataSet).当然也可以提高速度(不会立即写入硬盘或直接从硬盘中读出的数据马上显示),重复使用,最初最主要的目的是保护disk,

asp.net的cache有outputcahe与数据cache,主要目的是重复使用,提高速度,outputcache主要存储Reader后的页,一般是多次使用同一个HTML,建议不要varybyparam,不要存多version,

数据cache,如dataSet, dataTable,等

@page buffer="true",使用buffer,让buffer满后再显示读出或写入,(c中文件输出也是如此,主要目的是保护硬盘),也可以提高下次的访问速度.在client browse端表现是: true是一次性显示,要么不显示,中间等, false是一次显示一些,

这在网络输出也是如此表现.

对于文件访问c中默认采用的是buffer= true,这与asp.net一样,

相当于Response.write();中当buffer满后输出,以减少网络的传输次数

<%@ OutputCache Duration="60" VaryByParam="none"%>,是将asp.net生成的HTML缓存起来,在指定的时间内不需要重新生成html, control.ascx.也有组件缓存(htmlCach)。 dataSet也是如此。DataCache,

cache和buffer都是缓冲区,在翻译上,cache翻译成高速缓冲区要好一点(因为主要是为下次访问加速), buffer翻译成缓冲区好点。都是缓冲的作用,可目的有点不同,主要是理解,不需要太咬文嚼字.

cache和 buffer的区别

1, Buffer是缓冲区

2, Cache是高速缓存,分library cache; data dictionary cache; database buffer cache

Buffer cache缓冲区高速缓存,用于缓存从硬盘上读取的数据,减少磁盘I/O.

3, buffer有共享SQL区和PL/SQL区,数据库缓冲区高速缓存有独立的subcache

4, pool是共享池用于存储最近执行的语句等

5, cache:

A cache is a smaller, higher-speed component that is used to speed up the

access to commonly used data stored in a lower-speed, higher-capacity

component.

database buffer cache:

The database buffer cache is the portion of the SGA that holds copies of data

blocks

read from data files. All user processes concurrently(同时地,兼任地)connected

to the instance share access to the database buffer cache.

buffer cache就是以block为单位读入写出的。

缓存(cache)是把读取过的数据保存起来,重新读取时若命中(找到需要的数据)就不要去读硬盘了,若没有命中就读硬盘。其中的数据会根据读取频率进行组织,把最频繁读取的内容放在最容易找到的位置,把不再读的内容不断往后排,直至从中删除。

缓冲(buffers)是根据磁盘的读写设计的,把分散的写操作集中进行,减少磁盘碎片和硬盘的反复寻道,从而提高系统性能。linux有一个守护进程定期清空缓冲内容(即写如磁盘),也可以通过sync命令手动清空缓冲。举个例子吧:

我这里有一个ext2的U盘,我往里面cp一个3M的MP3,但U盘的灯没有跳动,过了一会儿(或者手动输入sync)U盘的灯

就跳动起来了。卸载设备时会清空缓冲,所以有些时候卸载一个设备时要等上几秒钟。

修改/etc/sysctl.conf中的vm.swappiness右边的数字可以在下次开机时调节swap使用策

略。该数字范围是0~100,数字越大越倾向于使用swap。默认为60,可以改一下试试。

-----------------------------------------

两者都是RAM中的数据。简单来说,buffer是即将要被写入磁盘的,而cache是被从磁盘中

读出来的。

buffer是由各种进程分配的,被用在如输入队列等方面,一个简单的例子如某个进程要求

有多个字段读入,在所有字段被读入完整之前,进程把先前读入的字段放在buffer中保存

cache经常被用在磁盘的I/O请求上,如果有多个进程都要访问某个文件,于是该文件便被

做成cache以方便下次被访问,这样可提供系统性能。

A buffer is something that has yet to be"written" to disk. A cache is

something that has been"read" from the disk and stored for later use.

更详细的解释参考:Difference Between Buffer and Cache

对于共享内存(Shared memory),主要用于在UNIX环境下不同进程之间共享数据,

是进程间通信的一种方法,一般的应用程序不会申请使用共享内存,笔者也没有去验证共

享内存对上面等式的影响。如果你有兴趣,请参考:What is Shared Memory?

cache和 buffer的区别:

Cache:高速缓存,是位于CPU与主内存间的一种容量较小但速度很高的存储器。由于

CPU的速度远高于主内存,CPU直接从内存中存取数据要等待一定时间周期, Cache中保存

着CPU刚用过或循环使用的一部分数据,当CPU再次使用该部分数据时可从Cache中直接调

用,这样就减少了CPU的等待时间,提高了系统的效率。Cache又分为一级Cache(L1 Cache)

和二级Cache(L2 Cache),L1 Cache集成在CPU内部,L2 Cache早期一般是焊在主板上,现

在也都集成在CPU内部,常见的容量有256KB或512KB L2 Cache。

Buffer:缓冲区,一个用于存储速度不同步的设备或优先级不同的设备之间传输数据

的区域。通过缓冲区,可以使进程之间的相互等待变少,从而使从速度慢的设备读入数据

时,速度快的设备的操作进程不发生间断。

Free中的buffer和cache:(它们都是占用内存):

buffer:作为buffer cache的内存,是块设备的读写缓冲区

cache:作为page cache的内存,文件系统的cache

如果 cache的值很大,说明cache住的文件数很多。如果频繁访问到的文件都能被

cache住,那么磁盘的读IO bi会非常小。

===========================================

# sync

# echo 1>/proc/sys/vm/drop_caches

echo 2>/proc/sys/vm/drop_caches

echo 3>/proc/sys/vm/drop_caches

cache释放:

To free pagecache:

echo 1>/proc/sys/vm/drop_caches

To free dentries and inodes:

echo 2>/proc/sys/vm/drop_caches

To free pagecache, dentries and inodes:

echo 3>/proc/sys/vm/drop_caches

说明,释放前最好sync一下,防止丢数据。

因为LINUX的内核机制,一般情况下不需要特意去释放已经使用的cache。这些cache起来的内容可以增加文件以及的读写速度。

阅读剩余
THE END