内核解读之内存管理(4)内存管理三级架构之page

news2025/1/10 1:22:15

我们前面介绍了linux内存管理的三级架构,node->zone->page。本节就来介绍page。

img

页是内核管理内存的基本单位,体系结构不同,支持的页大小也不尽相同,还有些体系结构甚至支持几种不同的页大小。大多数32位体系结构支持4KB的页,而64位体系结构一般会支持8KB的页。

内核用struct page结构描述系统中的每个物理页,

出于节省内存的考虑,struct page中使用了大量的联合体union,也导致page结构体理解起来比较复杂,对于不同的场景使用不同的union成员。最新版本的page结构体精简了好多。

struct page {
	unsigned long flags;		/* Atomic flags, some possibly
					 * updated asynchronously */ /* 描述page的状态和其他信息 */
	/*
	 * Five words (20/40 bytes) are available in this union.
	 * WARNING: bit 0 of the first word is used for PageTail(). That
	 * means the other users of this union MUST NOT use the bit to
	 * avoid collision and false-positive PageTail().
	 */
	union {
		struct {	/* Page cache and anonymous pages */
			/**
			 * @lru: Pageout list, eg. active_list protected by
			 * lruvec->lru_lock.  Sometimes used as a generic list
			 * by the page owner.
			 */
			union {
				struct list_head lru;

				/* Or, for the Unevictable "LRU list" slot */
				struct {
					/* Always even, to negate PageTail */
					void *__filler;
					/* Count page's or folio's mlocks */
					unsigned int mlock_count;
				};

				/* Or, free page */
				struct list_head buddy_list;
				struct list_head pcp_list;
			};
			/* See page-flags.h for PAGE_MAPPING_FLAGS */
			struct address_space *mapping;
			pgoff_t index;		/* Our offset within mapping. */
			/**
			 * @private: Mapping-private opaque data.
			 * Usually used for buffer_heads if PagePrivate.
			 * Used for swp_entry_t if PageSwapCache.
			 * Indicates order in the buddy system if PageBuddy.
			 */
			unsigned long private;
		};
        
        ... 删了一堆不常用的
            
		/** @rcu_head: You can use this to free a page by RCU. */
		struct rcu_head rcu_head;
	};

	union {		/* This union is 4 bytes in size. */
		/*
		 * If the page can be mapped to userspace, encodes the number
		 * of times this page is referenced by a page table.
		 */
		atomic_t _mapcount;

		/*
		 * If the page is neither PageSlab nor mappable to userspace,
		 * the value stored here may help determine what this page
		 * is used for.  See page-flags.h for a list of page types
		 * which are currently stored here.
		 */
		unsigned int page_type;
	};

	/* Usage count. *DO NOT USE DIRECTLY*. See page_ref.h */
	atomic_t _refcount;

	...省略了一堆开启配置才有的成员
} _struct_page_alignment;

flags

第一个成员flags是所有page都有的

page的flags标识主要分为4部分,其中标志位flag向高位增长, 其余位字段向低位增长,中间存在空闲位

字段 描述
section 稀疏内存模型标识该page哪个section
node NUMA节点号, 标识该page属于哪一个节点
zone 内存域标志,标识该page属于哪一个zone
flag page的状态标识

page的flags标识

配套的转换函数:

static inline void set_page_zone(struct page *page, enum zone_type zone)
{
	page->flags &= ~(ZONES_MASK << ZONES_PGSHIFT);
	page->flags |= (zone & ZONES_MASK) << ZONES_PGSHIFT;
}

static inline void set_page_node(struct page *page, unsigned long node)
{
	page->flags &= ~(NODES_MASK << NODES_PGSHIFT);
	page->flags |= (node & NODES_MASK) << NODES_PGSHIFT;
}

#ifdef SECTION_IN_PAGE_FLAGS
static inline void set_page_section(struct page *page, unsigned long section)
{
	page->flags &= ~(SECTIONS_MASK << SECTIONS_PGSHIFT);
	page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
}

static inline unsigned long page_to_section(const struct page *page)
{
	return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
}
#endif

page状态定义如下:

/*
 * Don't use the pageflags directly.  Use the PageFoo macros.
 *
 * The page flags field is split into two parts, the main flags area
 * which extends from the low bits upwards, and the fields area which
 * extends from the high bits downwards.
 *
 *  | FIELD | ... | FLAGS |
 *  N-1           ^       0
 *               (NR_PAGEFLAGS)
 *
 * The fields area is reserved for fields mapping zone, node (for NUMA) and
 * SPARSEMEM section (for variants of SPARSEMEM that require section ids like
 * SPARSEMEM_EXTREME with !SPARSEMEM_VMEMMAP).
 */
enum pageflags {
	PG_locked,		/* Page is locked. Don't touch. */
	PG_referenced,
	PG_uptodate,
	PG_dirty,
	PG_lru,
	PG_active,
	PG_workingset,
	PG_waiters,		/* Page has waiters, check its waitqueue. Must be bit #7 and in the same byte as "PG_locked" */
	PG_error,
	PG_slab,
	PG_owner_priv_1,	/* Owner use. If pagecache, fs may use*/
	PG_arch_1,
	PG_reserved,
	PG_private,		/* If pagecache, has fs-private data */
	PG_private_2,		/* If pagecache, has fs aux data */
	PG_writeback,		/* Page is under writeback */
	PG_head,		/* A head page */
	PG_mappedtodisk,	/* Has blocks allocated on-disk */
	PG_reclaim,		/* To be reclaimed asap */
	PG_swapbacked,		/* Page is backed by RAM/swap */
	PG_unevictable,		/* Page is "unevictable"  */
#ifdef CONFIG_MMU
	PG_mlocked,		/* Page is vma mlocked */
#endif
#ifdef CONFIG_ARCH_USES_PG_UNCACHED
	PG_uncached,		/* Page has been mapped as uncached */
#endif
#ifdef CONFIG_MEMORY_FAILURE
	PG_hwpoison,		/* hardware poisoned page. Don't touch */
#endif
#if defined(CONFIG_PAGE_IDLE_FLAG) && defined(CONFIG_64BIT)
	PG_young,
	PG_idle,
#endif
#ifdef CONFIG_64BIT
	PG_arch_2,
#endif
#ifdef CONFIG_KASAN_HW_TAGS
	PG_skip_kasan_poison,
#endif
	__NR_PAGEFLAGS,

	PG_readahead = PG_reclaim,

	/*
	 * Depending on the way an anonymous folio can be mapped into a page
	 * table (e.g., single PMD/PUD/CONT of the head page vs. PTE-mapped
	 * THP), PG_anon_exclusive may be set only for the head page or for
	 * tail pages of an anonymous folio. For now, we only expect it to be
	 * set on tail pages for PTE-mapped THP.
	 */
	PG_anon_exclusive = PG_mappedtodisk,

	/* Filesystems */
	PG_checked = PG_owner_priv_1,

	/* SwapBacked */
	PG_swapcache = PG_owner_priv_1,	/* Swap page: swp_entry_t in private */

	/* Two page bits are conscripted by FS-Cache to maintain local caching
	 * state.  These bits are set on pages belonging to the netfs's inodes
	 * when those inodes are being locally cached.
	 */
	PG_fscache = PG_private_2,	/* page backed by cache */

	/* XEN */
	/* Pinned in Xen as a read-only pagetable page. */
	PG_pinned = PG_owner_priv_1,
	/* Pinned as part of domain save (see xen_mm_pin_all()). */
	PG_savepinned = PG_dirty,
	/* Has a grant mapping of another (foreign) domain's page. */
	PG_foreign = PG_owner_priv_1,
	/* Remapped by swiotlb-xen. */
	PG_xen_remapped = PG_owner_priv_1,

	/* SLOB */
	PG_slob_free = PG_private,

	/* Compound pages. Stored in first tail page's flags */
	PG_double_map = PG_workingset,

#ifdef CONFIG_MEMORY_FAILURE
	/*
	 * Compound pages. Stored in first tail page's flags.
	 * Indicates that at least one subpage is hwpoisoned in the
	 * THP.
	 */
	PG_has_hwpoisoned = PG_error,
#endif

	/* non-lru isolated movable page */
	PG_isolated = PG_reclaim,

	/* Only valid for buddy pages. Used to track pages that are reported */
	PG_reported = PG_uptodate,

#ifdef CONFIG_MEMORY_HOTPLUG
	/* For self-hosted memmap pages */
	PG_vmemmap_self_hosted = PG_owner_priv_1,
#endif
};

第二个成员,比较复杂的联合体,此处我删除了一些不常用的场景,

先看第一个场景:用于page cache和匿名页。

什么是匿名页?

应用程序动态分配的堆内存称为匿名页(Anonymous Page)
堆内存很可能还要再次被访问,当然不能直接回收了。这些内存自然不能直接释放。

什么是page cache?

磁盘中一个文件或者其他虚拟文件(shmem)加载到内存所对应的page。

这个页可能在lru上,可能在伙伴系统里,可能在pcp链表里,可能看到三种都是互斥的,这三种都是内核管理内存的方式,只是用于不同的场景需要。这么来看,还是挺清晰的。

	/*
	 * Five words (20/40 bytes) are available in this union.
	 * WARNING: bit 0 of the first word is used for PageTail(). That
	 * means the other users of this union MUST NOT use the bit to
	 * avoid collision and false-positive PageTail().
	 */
	union {
		struct {	/* Page cache and anonymous pages */
			/**
			 * @lru: Pageout list, eg. active_list protected by
			 * lruvec->lru_lock.  Sometimes used as a generic list
			 * by the page owner.
			 */
			union {
				struct list_head lru;

				/* Or, for the Unevictable "LRU list" slot */
				struct {
					/* Always even, to negate PageTail */
					void *__filler;
					/* Count page's or folio's mlocks */
					unsigned int mlock_count;
				};

				/* Or, free page */
				struct list_head buddy_list;
				struct list_head pcp_list;
			};
			/* See page-flags.h for PAGE_MAPPING_FLAGS */
			struct address_space *mapping;
			pgoff_t index;		/* Our offset within mapping. */
			/**
			 * @private: Mapping-private opaque data.
			 * Usually used for buffer_heads if PagePrivate.
			 * Used for swp_entry_t if PageSwapCache.
			 * Indicates order in the buddy system if PageBuddy.
			 */
			unsigned long private;
		};
		...

		struct {	/* Page table pages */
			unsigned long _pt_pad_1;	/* compound_head */
			pgtable_t pmd_huge_pte; /* protected by page->ptl */
			unsigned long _pt_pad_2;	/* mapping */
			union {
				struct mm_struct *pt_mm; /* x86 pgds only */
				atomic_t pt_frag_refcount; /* powerpc */
			};
#if ALLOC_SPLIT_PTLOCKS
			spinlock_t *ptl;
#else
			spinlock_t ptl;
#endif
		};

		/** @rcu_head: You can use this to free a page by RCU. */
		struct rcu_head rcu_head;
	};

上面有一个非常非常重要的成员,struct address_space *mapping;,磁盘中一个文件或者其他虚拟文件(shmem)所对应的page每次都是经过同一个struct address_space来进行管理。

index在映射的虚拟空间(vma_area)内的偏移;一个文件可能只映射一部分,假设映射了1M的空间,index指的是在1M空间内的偏移,而不是在整个文件内的偏移

private私有数据指针,由应用场景确定其具体的含义

  1. 如果设置了PG_private标志,则private字段指向struct buffer_head
  2. 如果设置了PG_swapcache标志,private存储了该page在交换分区中对应的位置信息swp_entry_t。
  3. 如果设置了PageBuddy标志,说明该page位于伙伴系统,private存储该伙伴的阶

页的第二个场景,用于存放页表。


第三个成员,联合体:

	union {		/* This union is 4 bytes in size. */
		/*
		 * If the page can be mapped to userspace, encodes the number
		 * of times this page is referenced by a page table.
		 */
		atomic_t _mapcount;

		/*
		 * If the page is neither PageSlab nor mappable to userspace,
		 * the value stored here may help determine what this page
		 * is used for.  See page-flags.h for a list of page types
		 * which are currently stored here.
		 */
		unsigned int page_type;
	};

被页表映射的次数,也就是说该page同时被多少个进程共享。初始值为-1,如果只被一个进程的页表映射了,该值为0. 如果该page处于伙伴系统中,该值为PAGE_BUDDY_MAPCOUNT_VALUE(-128),内核通过判断该值是否为PAGE_BUDDY_MAPCOUNT_VALUE来确定该page是否属于伙伴系统


第四个成员,所有page都有的成员:

atomic_t _refcount;

引用计数,表示内核中引用该page的次数, 如果要操作该page, 引用计数会+1, 操作完成-1. 当该值为0时, 表示没有引用该page的位置,所以该page可以被解除映射,这往往在内存回收时是有用的

page_ref.h定义了配套的操作函数:

static inline int page_ref_count(const struct page *page)
{
	return atomic_read(&page->_refcount);
}

static inline void set_page_count(struct page *page, int v)
{
	atomic_set(&page->_refcount, v);
	if (page_ref_tracepoint_active(page_ref_set))
		__page_ref_set(page, v);
}

...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/146499.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python】爬取弹幕并保存到Excel中

hello&#xff0c;我是李华同学&#xff0c;最近开始学习爬虫&#xff0c;下面是我实现的一个得到弹幕的代码&#x1f60f;找一个URL&#x1f449;想要得到一个网站的内容&#xff0c;首先要找到你想要内容的具体位置&#xff0c;首先你先找到一个有弹幕的地方&#xff0c;找到…

linux系统重装yum工具与python环境

文章目录前言一、强制删除原有环境1.删除python2.删除yum二、安装新环境前置准备三、下载依赖命令1.内核版本7.6.1810下载python依赖包下载yum包2.内核版本7.4.1708下载python依赖包下载yum包3.内核版本7.8.2003下载python依赖包下载yum依赖包4.下载结果四、安装前言 安装之前…

swagger入门

目录 1.前后端分离的特点 2.在没有swagger之前 3.swagger的作用 4.swagger的优点 5.集成swagger 5.1 新建springboot项目 5.2 集成swagger 5.3 开发一个controller用于测试 5.4 启动服务&#xff0c;验证集成效果 6.swagger常用注解 7.swagger使用综合案例 8.会议OA之sw…

第三章 Flink DataStream API

Flink 系列教程传送门 第一章 Flink 简介 第二章 Flink 环境部署 第三章 Flink DataStream API 第四章 Flink 窗口和水位线 第五章 Flink Table API&SQL 第六章 新闻热搜实时分析系统 一、DataStream API是什么&#xff1f; Flink 中的 DataStream 程序是对数据流&a…

Android 深入系统完全讲解(2)

1 系统启动过程、嵌入式系统启动过程 这是我之前画的启动过程的图&#xff0c;这个主要就是给大家讲明白&#xff0c;启动过程整个的流程。 第一个阶段&#xff0c;bootloader 系统在上电的时候&#xff0c;系统会从固定的地方加载一段代码进入内部 ram 进行运行。这段代码 通…

【数学思维】Quasi-convex and quesi-concave

【数学思维】Quasi-convex and quesi-concaveConvex function 定义如下 f(λx(1−λ)y)≤λf(x)(1−λ)f(y)f(\lambda x(1-\lambda)y)\le \lambda f(x)(1-\lambda)f(y) f(λx(1−λ)y)≤λf(x)(1−λ)f(y)Quasi-convex function 定义如下 f(λx(1−λ)y)≤max⁡{f(x),f(y)}f(\l…

【阶段三】Python机器学习01篇:机器学习概念、机器学习类别、机器学习应用场景与机器学习基本技术:特征、标签、模型

本篇的思维导图: 机器学习概念 机器学习是AI人工智能的分支技术,而深度学习是机器学习的重要分支。 人工智能、机器学习、深度学习三者的关系 机器学习就是从数据中发现规律,机器学习的关键内涵之一在于利用计算机的运算能力从大量的数据中发现一个“函数”或…

Linux——VMware Tools的介绍及安装方法

一、VMware Tools的作用 1.最大的好处是可以直接把windows界面的文件拖进linux虚拟机内。 2.鼠标可以直接从虚拟机移动到windows等等好处。 二、VMware Tools的安装步骤 1.首先把linux虚拟机关机或退出&#xff0c;然后点击“编辑虚拟机设置”。 2.点击CD/DVD&#xff0c;…

电子、半导体废水深度除氟、除重金属的技术详解

电子半导体行业废水来源及水质特点电子废水主要是印刷线路板中每个环节产生的废水&#xff0c;如线路板上的赋铜线路、电子元器件、二极管、三极管、电容等&#xff0c;日常生活中常见的就是电脑元器件&#xff0c;如内存条、CPU、主板等。这些东西在生产成型的过程中主要通过电…

968. 监控二叉树

题目 分析 首先明确把摄像头放在叶子节点的父节点位置&#xff0c;才能充分利用摄像头的覆盖面积。 贪心算法&#xff1a; 从下到上看局部最优&#xff0c;因为下面的节点最多&#xff0c;让叶子节点的父节点安摄像头最合理&#xff0c;所用摄像头最少。 整体全局最优&#xf…

基于融合SPD+BIFPN+CBAM改进YOLOv5的奶牛检测识别分析系统开发

在我之前的几篇文章中分别应用了不同的tricks来改进yolov5模型如下&#xff1a;加入针对小目标的SPD-Conv模块《yolov5s融合SPD-Conv用于提升小目标和低分辨率图像检测性能实践五子棋检测识别》加入BIFPN特征融合模块《基于yolov5sbifpn实践隧道裂缝裂痕检测》加入注意力机制模…

[数据结构]栈和队列

目录[数据结构]栈和队列一.栈1.栈的基本概念1.2 栈的常见基本操作1.3 栈的实现1.3.1 入栈1.3.2 出栈1.3.3获取栈顶元素1.3.4 判断栈为空1.3.5 栈实现二.队列2.1 入队2.2 出队2.3 获取队首元素2.4 实现队列[数据结构]栈和队列 一.栈 1.栈的基本概念 栈&#xff08;Stack&#…

你了解真正的数字孪生吗?

数字孪生的目的是在虚拟空间构建数字化的复杂系统“镜像”&#xff0c;可以低成本、反复的从多个视角观察、控制、分析、验证和推演&#xff0c;从而帮助人们更好的在现实世界中完成设计、生产、运营等活动。 近年来&#xff0c;数字孪生技术在航空航天、工业制造、交通物流等多…

hbase2.x HBCK Report Region Holes Overlaps问题修复

Region Holes 查看该问题可通过master UI界面的HBCK Report查看 最下方RegionInfo展示了哪两个region之间存在空洞 也可以通过master日志查看 解决步骤 解决方法很简单&#xff0c;直接使用 hbck2 提供的 fixMeta 操作即可。 在 Usage 说明中能看到 fixMeta 能够修复 ‘…

【Linux】make/Makefile的使用

本文目录 背景简介 使用方法 为什么执行的指令是make和make clean呢&#xff1f; gcc如何判断文件是否需要重新执行&#xff1f; 背景简介 一个工程中的源文件不计数&#xff0c;其按类型、功能、模块分别放在若干个目录中&#xff0c;makefifile定义了一系列的规则来指定…

16万字智慧医疗-医院信息化大数据建设 方案

【版权声明】本资料来源网络&#xff0c;知识分享&#xff0c;仅供个人学习&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间删除&#xff01;完整资料领取见文末&#xff0c;部分资料内容&#xff1a; 目 录 1 概述 1.1 现状分析 …

人工智能-网络编程、TCP

目录1、网络编程1.1网络介绍1.2IP地址1.3 ifconfig和ping命名1.4端口和端口号1.5端口号的分类1.6 socket介绍1.7 TCP介绍&#xff12;、TCP的网络应用程序开发2.1 python&#xff13;编码转换2.2 TCP客户端程序开发流程2.3 TCP客户端程序开发2.4 TCP服务端程序开发流程2.5 TCP…

[Android]序列化原理Parcelable

Parcelable是Android为我们提供的序列化的接口&#xff0c;Parcelable相对于Serializable的使用相对复杂一些&#xff0c;但Parcelable的效率相对Serializable也高很多&#xff0c;这一直是Google工程师引以为傲的&#xff0c;Parcelable和Serializable的效率对比Parcelable vs…

CesiumLab中对输入人工模型的格式要求 CesiumLab系列教程

人工模型数据&#xff08;或者手工模型数据&#xff09;是三维 GIS 行业发展的最早的需求来源&#xff0c;通过3dsmax&#xff0c;maya 等建模工具人工建模的数据。 ​ 编辑 人工模型 这张图是cesiumlab上对人工模型来源的流程&#xff0c;在上面我们只罗列了四个建模工具&a…

Rabbitmq消息队列详解(二)——消息模式API

官网提供的消息模式&#xff1a; 依赖&#xff1a; <!-- 加入rabbitmq --> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency>hello模型 没有交换机&…