Linux内存管理宏观篇(三)物理内存:物理页面

简介: Linux内存管理宏观篇(三)物理内存:物理页面

前言

关于物理内存,物理,那肯定是事物,实实在在的东西。对于这种实在的,就需要进行管理,而管理肯定是软件来管理。

对于物理内存怎么管理?

涉及到的无非就是怎么分配内存、怎么回收整理内存、怎么样提高分配效率、怎么减少浪费?

带着这几个想法,我们往下瞅瞅。

首先来看看物理页面是什么?

1、物理页面

前面我们对页这个机制有了映像,这里的物理页面就是对物理内存以页面的分配机制。现在我们都知道处理器是有个MMU硬件模块,会将虚拟内存映射到物理内存,映射的单位就是页。虚拟内存页,到物理内存页。

页面的大小常见的有4KB,但是还有8、16、64KB等。

管理内存的最小单元就是页,对于这个页面的管理,在linux中有个struct_page数据结构来描述物理页面。

来看看结构,这里将复杂的联合体暂时隐藏了。

struct page {
  unsigned long     flags;
  atomic_t        _count;
  atomic_t        _mapcount;
  unsigned long     private;
  struct address_space *mapping;
  pgoff_t         index;
  struct list_head    lru;
  void           *virtual;
}

下面来看看这些标志位代表什么?

1.1、标志 flags

flags成员是页面的标志位集合。具体定义在include/linux/page-flags.h文件中。

0 enum pageflags {
  1  PG_locked,      /* 页面已经上锁,不要访问 */
  2  PG_error, /*表示页面发生了I/O错误*/
  3  PG_referenced, /*该标志位用来实现LRU算法中的第二次机会法,详见7.6节*/
  4  PG_uptodate, /*表示页面内容是有效的,当该页面上的读操作完成后,设置该标志位*/
  5  PG_dirty, /*表示页面内容被修改过,为脏页*/
  6  PG_lru, /*表示该页在LRU链表中*/
  7  PG_active, /*表示该页在活跃LRU链表中*/
  8  PG_slab, /*表示该页属于由slab分配器创建的slab*/
  9  PG_owner_priv_1, /* 页面的所有者使用,如果是pagecache页面,文件系统可能使用*/
  10 PG_arch_1, /*与体系结构相关的页面状态位*/
  11 PG_reserved, /*表示该页不可被换出*/
  12 PG_private,/* 表示该页是有效的,当page->private包含有效值时会设置该标志位。如果页面是pagecache,那么包含一些文件系统相关的数据信息*/
  13 PG_private_2, /* 如果是pagecache, 可能包含fs aux data */
  14 PG_writeback,     /* 页面正在回写 */
  15 PG_compound,      /* 一个混合页面*/
  16 PG_swapcache,     /* 这是交换页面 */
  17 PG_mappedtodisk,   /* 在磁盘中分配了blocks */
  18 PG_reclaim,      /* 马上要被回收了 */
  19 PG_swapbacked,     /* 页面支持RAM/swap */
  20 PG_unevictable,    /* 页面是不可收回的*/
  21#ifdef CONFIG_MMU
  22 PG_mlocked,      /* vma处于mlocked状态 */
  23#endif
  24 __NR_PAGEFLAGS,
  25};

这个里面全是标志位,等到用到的时候知道在这里就行。

你是不是以为flags里面只有标志,非也非也。flags另外一个重要作用是可以存放section编号、node编号、zone编号、last_cpuid等。但是关于flags具体到底放的什么?这与内核的配置有关系,

例如 SECTION 编号和 NODE 编号与CONFIG_SPARSEMEM/CONFIG_SPARSEMEM_VMEMMAP配置相关,LAST_CPUPID与CONFIG_NUMA_BALA NCING配置相关。(这里可以看看之前我写的linux内核学习makefile和.config文件)

1.2、 _count和_mapcount 引用计数

_count:表示内核中有多少操作引用这个页面

当引用计数为0说明页面为空闲,那就说明这页面可以被释放了。
内核中常用的加减_count 引用计数的API 为 
get_page()、put_page()、page_cache_get()以及page_cache_release()函数。

_mapcount:表示页面被进程映射的次数,用户页表(pte页表),进程每个是独立的虚拟内存(3G的虚拟空间和独立页表),这就可能存在多个进程都访问一片物理页面。

_mapcount等于−1,表示没有pte映射到页面中。

_mapcount 等于 0,表示只有父进程映射了页面。匿名页面刚分配时,_mapcount引用计数初始化为0。

RMAP反向映射机制就是利用这个特性来实现的。_mapcount引用计数主要用于RMAP反向映射机制中。(通过反向看看这个物理页面还有人用吗?)RMAP就是看这个的值。

对于这两个计数值,很多内核的操作都需要这两个值,比如页面分配机制、反向映射机制、页面回收机制等,因此它是管理物理页面的核心机制。

_count和_mapcount都是atomic_t类型的变量

当需要获得_count和_mapcount的计数值,就采用内核提供的两个宏来统计某个页面的_count和_mapcount的计数。

static inline int page_mapcount(struct page *page)
static inline int page_count(struct page *page)

1.3、mapping字段

用于文件缓存(page cache) :mapping指向和相关联的address_space对象

  • address_space :内存对象(比如索引节点)的页面集合

用于匿名页面(anonymous page):mapping指向anon_vma数据结构。

  • anon_vma数据结构

1.4、lru字段

lru字段主要用在页面回收的LRU链表算法中。

LRU链表算法定义了多个链表,比如活跃链表(Active list)和非活跃链表(Inactive list)等。

在slab机制中,该字段也被用来把一个slab添加到slab满链表、slab空闲链表和slab部分满链表中。

利用这个字段将页面挂接不同链表上?

1.5、virtual字段

这个一看就知道是和虚拟内存有关系,这个是物理页面映射的虚拟内存的地址指针。

当需要动态映射这些高端内存时,字段的值才不位NULL。

当不是高端地址,我们知道物理地址和虚拟地址存在一段线性区,这里这个值就为NULL

因此可以通过这个字段判断这个页面是否是线性映射过来的。

(对于高端任然有丢丢迷惑:1GB内除了768MB的线性区,剩下到1GB的空间叫高端,还是1GB-3GB叫高端,还是两者加起来都是,这里感觉应该是后两者都合适,最后一点更符合。)

2、小结

通过上面的位我们可以得到:

得到页面状态

是否空闲页面

有多少进程在使用

谁在使用页面

页面是否被slab机制使用

这个页面是否是线性映射

我们知道很多页面的属性,但是就页面本身还是没有涉及到。

这是因为内核是给每一个页面分配了一个struct page数据结构,采用mem_map[]数组来存放,其和物理页面是一一对应。因此就不需要再在结构体里用额外的数据描述页面物理地址。(看到这个map就有一对一的感觉了撒)

struct page数据结构的mem_map[]数组定义在 mm/memory.c文件中,

它的初始化在free_area_init_node()->alloc_node_mem_map()函数中。

struct page *mem_map;
EXPORT_SYMBOL(mem_map);

每个物理页面都对应一个struct page数据结构,因此内核社区对于struct page数据结构的大小管控相当严格。

struct page 数据结构大小通常是几十字节,而一个物理页面是 4096字节,假设struct page数据结构占用40字节,那么就相当于要浪费百分之一的内存来存放这些struct page数据结构。

因此,如果在struct page数据结构新增一个变量或者指针,那么系统相当于需要额外千分之一的内存来存放这个新增的指针。假设系统是10GB内存,就要浪费10MB的内存,这种情况挺可怕的。

以上就是物理内存页,下一篇来讲讲物理内存的管理,小少爷辛苦了,休息一下吧。

参考资料:

《奔跑吧 Linux内核》

目录
相关文章
|
缓存 Linux
linux 手动释放内存
在 Linux 系统中,内存管理通常自动处理,但业务繁忙时缓存占用过多可能导致内存不足,影响性能。此时可在业务闲时手动释放内存。
966 17
|
11月前
|
缓存 监控 Linux
Linux内存问题排查命令详解
Linux服务器卡顿?可能是内存问题。掌握free、vmstat、sar三大命令,快速排查内存使用情况。free查看实时内存,vmstat诊断系统整体性能瓶颈,sar实现长期监控,三者结合,高效定位并解决内存问题。
975 0
Linux内存问题排查命令详解
|
缓存 Linux 数据安全/隐私保护
Linux环境下如何通过手动调用drop_caches命令释放内存
总的来说,记录住“drop_caches” 命令并理解其含义,可以让你在日常使用Linux的过程中更加娴熟和自如。
2031 23
|
监控 Linux 开发者
理解Linux操作系统内核中物理设备驱动(phy driver)的功能。
综合来看,物理设备驱动在Linux系统中的作用是至关重要的,它通过与硬件设备的紧密配合,为上层应用提供稳定可靠的通信基础设施。开发一款优秀的物理设备驱动需要开发者具备深厚的硬件知识、熟练的编程技能以及对Linux内核架构的深入理解,以确保驱动程序能在不同的硬件平台和网络条件下都能提供最优的性能。
624 0
|
消息中间件 Linux
Linux中的System V通信标准--共享内存、消息队列以及信号量
希望本文能帮助您更好地理解和应用System V IPC机制,构建高效的Linux应用程序。
646 48
|
监控 Linux Python
Linux系统资源管理:多角度查看内存使用情况。
要知道,透过内存管理的窗口,我们可以洞察到Linux系统运行的真实身姿,如同解剖学家透过微观镜,洞察生命的奥秘。记住,不要惧怕那些高深的命令和参数,他们只是你掌握系统"魔法棒"的钥匙,熟练掌握后,你就可以骄傲地说:Linux,我来了!
530 27
|
缓存 NoSQL Linux
Linux系统内存使用优化技巧
交换空间(Swap)的优化 禁用 Swap sudo swapoff -a 作用:这个命令会禁用系统中所有的 Swap 空间。swapoff 命令用于关闭 Swap 空间,-a 参数表示关闭 /etc/fstab 文件中配置的所有 Swap 空间。 使用场景:在高性能应用场景下,比如数据库服务器或高性能计算服务器,禁用 Swap 可以减少磁盘 I/O,提高系统性能。
634 3
|
算法 Linux
深入探索Linux内核的内存管理机制
本文旨在为读者提供对Linux操作系统内核中内存管理机制的深入理解。通过探讨Linux内核如何高效地分配、回收和优化内存资源,我们揭示了这一复杂系统背后的原理及其对系统性能的影响。不同于常规的摘要,本文将直接进入主题,不包含背景信息或研究目的等标准部分,而是专注于技术细节和实际操作。
549 35
|
存储 监控 算法
Java内存管理深度剖析:从垃圾收集到内存泄漏的全面指南####
本文深入探讨了Java虚拟机(JVM)中的内存管理机制,特别是垃圾收集(GC)的工作原理及其调优策略。不同于传统的摘要概述,本文将通过实际案例分析,揭示内存泄漏的根源与预防措施,为开发者提供实战中的优化建议,旨在帮助读者构建高效、稳定的Java应用。 ####
339 35
|
缓存 Linux
Linux查看内存命令
1. free free命令是最常用的查看内存使用情况的命令。它显示系统的总内存、已使用内存、空闲内存和交换内存的总量。 free -h • -h 选项:以易读的格式(如GB、MB)显示内存大小。 输出示例: total used free shared buff/cache available Mem: 15Gi 4.7Gi 4.1Gi 288Mi 6.6Gi 9.9Gi Swap: 2.0Gi 0B 2.0Gi • to
3723 2