【linux kernel】linux内存管理 | 分配物理内存页面

article/2025/10/11 12:30:59

文章目录

        • 一、物理内存分配概述
        • 二、分配核心函数(__alloc_pages_nodemask)
          • (2-1)重要函数1:(get_page_from_freelist())
            • (2-2-1)for_each_zone_zonelist_nodemask{}
          • (2-2)重要函数2:(__alloc_pages_slowpath())
        • 三、分配掩码
          • (3-1)分配掩码宏定义
          • (3-2)宏定义组合
        • 四、总结

👀 注:以下代码片段出自linux内核版本:4.1.15

一、物理内存分配概述

​ 在linux内核中,页面分配器用于分配出一个或者多个连续的物理页面。分配的页面个数只能是2的整数次幂;分配连续的物理页面要比分配离散的物理页面更有利于缓解系统的内存碎片化。

​ linux内核中常使用的内存分配API函数如下:

//只分配1个page,返回指向第一page结构的指针
alloc_page() //分配2^order个page,返回指向第一page结构的指针
alloc_pages()//只分配1个page,返回该page所在的虚拟地址的指针
__get_free_page()//配2^order个page,返回指向第一page结构的虚拟地址的指针
__get_free_pages()//只分配1个page,让内容填充为0,返回该page所在的虚拟地址的指针
get_zeroed_page()	
__get_dma_pages()

​ 上述这些函数都将调用到一个共同函数:__alloc_pages_nodemask()。该函数是linux分配内存的核心函数。

二、分配核心函数(__alloc_pages_nodemask)

__alloc_pages_nodemask()函数原型:

struct page *__alloc_pages_nodemask
(gfp_t gfp_mask, 			//分配掩码unsigned int order,			//分配阶数struct zonelist *zonelist,  //zone链表nodemask_t *nodemask		//node掩码
)

函数定义(/mm/page_alloc.c):

struct page *__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,struct zonelist *zonelist, nodemask_t *nodemask)
{struct zoneref *preferred_zoneref;struct page *page = NULL;unsigned int cpuset_mems_cookie;int alloc_flags = ALLOC_WMARK_LOW|ALLOC_CPUSET|ALLOC_FAIR;gfp_t alloc_mask; /* The gfp_t that was actually used for allocation *///struct alloc_context数据结构用于保存分配相关参数。struct alloc_context ac = {//gfp_zone()函数将从分配掩码中计算出zoneidx,并存放于high_zoneidx结构成员中。.high_zoneidx = gfp_zone(gfp_mask),//将nodemask进行保存到ac中.nodemask = nodemask,//把gfp_mask掩码转换成MIGRATE_TYPES类型,并存放于migratetype结构成员中。.migratetype = gfpflags_to_migratetype(gfp_mask),};gfp_mask &= gfp_allowed_mask;lockdep_trace_alloc(gfp_mask);might_sleep_if(gfp_mask & __GFP_WAIT);if (should_fail_alloc_page(gfp_mask, order))return NULL;/** Check the zones suitable for the gfp_mask contain at least one* valid zone. It's possible to have an empty zonelist as a result* of __GFP_THISNODE and a memoryless node*/if (unlikely(!zonelist->_zonerefs->zone))return NULL;if (IS_ENABLED(CONFIG_CMA) && ac.migratetype == MIGRATE_MOVABLE)alloc_flags |= ALLOC_CMA;retry_cpuset:cpuset_mems_cookie = read_mems_allowed_begin();//将zonelist保存到ac中,因为在__alloc_pages_slowpath函数中可能会改变zonelistac.zonelist = zonelist;/* The preferred zone is used for statistics later */preferred_zoneref = first_zones_zonelist(ac.zonelist, ac.high_zoneidx,ac.nodemask ? : &cpuset_current_mems_allowed,&ac.preferred_zone);if (!ac.preferred_zone)goto out;ac.classzone_idx = zonelist_zone_idx(preferred_zoneref);//设置分配掩码alloc_mask = gfp_mask|__GFP_HARDWALL;page = get_page_from_freelist(alloc_mask, order, alloc_flags, &ac);if (unlikely(!page)) {//设置分配掩码为noio标志。 因为设备上的I/O可能还没有执行完成,运行时PM、block IO以及其错误处理路径可能将导致死锁。alloc_mask = memalloc_noio_flags(gfp_mask);page = __alloc_pages_slowpath(alloc_mask, order, &ac);}if (kmemcheck_enabled && page)kmemcheck_pagealloc_alloc(page, order, gfp_mask);trace_mm_page_alloc(page, order, alloc_mask, ac.migratetype);out:/** When updating a task's mems_allowed, it is possible to race with* parallel threads in such a way that an allocation can fail while* the mask is being updated. If a page allocation is about to fail,* check if the cpuset changed during allocation and if so, retry.*/if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))goto retry_cpuset;return page;
}

上述函数中调用get_page_from_freelist(alloc_mask, order, alloc_flags, &ac);去尝试分配物理页面。

当未能成功分配页面时,将进入以下所示的代码片段:

alloc_mask = memalloc_noio_flags(gfp_mask);
page = __alloc_pages_slowpath(alloc_mask, order, &ac);

__alloc_pages_slowpath()函数中将处理很多特殊场景,且该函数也较复杂,此处暂且打住。

(2-1)重要函数1:(get_page_from_freelist())

get_page_from_freelist()函数定义如下(/mm/page_alloc.c):

static struct page *
get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,const struct alloc_context *ac)
{struct zonelist *zonelist = ac->zonelist;struct zoneref *z;struct page *page = NULL;struct zone *zone;nodemask_t *allowednodes = NULL;/* zonelist_cache approximation */int zlc_active = 0;		/* set if using zonelist_cache */int did_zlc_setup = 0;		/* just call zlc_setup() one time */bool consider_zone_dirty = (alloc_flags & ALLOC_WMARK_LOW) &&(gfp_mask & __GFP_WRITE);int nr_fair_skipped = 0;bool zonelist_rescan;zonelist_scan:zonelist_rescan = false;/** Scan zonelist, looking for a zone with enough free.* See also __cpuset_node_allowed() comment in kernel/cpuset.c.*/for_each_zone_zonelist_nodemask(zone, z, zonelist, ac->high_zoneidx,ac->nodemask) {unsigned long mark;if (IS_ENABLED(CONFIG_NUMA) && zlc_active &&!zlc_zone_worth_trying(zonelist, z, allowednodes))continue;if (cpusets_enabled() &&(alloc_flags & ALLOC_CPUSET) &&!cpuset_zone_allowed(zone, gfp_mask))continue;/** Distribute pages in proportion to the individual* zone size to ensure fair page aging.  The zone a* page was allocated in should have no effect on the* time the page has in memory before being reclaimed.*/if (alloc_flags & ALLOC_FAIR) {if (!zone_local(ac->preferred_zone, zone))break;if (test_bit(ZONE_FAIR_DEPLETED, &zone->flags)) {nr_fair_skipped++;continue;}}/** When allocating a page cache page for writing, we* want to get it from a zone that is within its dirty* limit, such that no single zone holds more than its* proportional share of globally allowed dirty pages.* The dirty limits take into account the zone's* lowmem reserves and high watermark so that kswapd* should be able to balance it without having to* write pages from its LRU list.** This may look like it could increase pressure on* lower zones by failing allocations in higher zones* before they are full.  But the pages that do spill* over are limited as the lower zones are protected* by this very same mechanism.  It should not become* a practical burden to them.** XXX: For now, allow allocations to potentially* exceed the per-zone dirty limit in the slowpath* (ALLOC_WMARK_LOW unset) before going into reclaim,* which is important when on a NUMA setup the allowed* zones are together not big enough to reach the* global limit.  The proper fix for these situations* will require awareness of zones in the* dirty-throttling and the flusher threads.*/if (consider_zone_dirty && !zone_dirty_ok(zone))continue;mark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK];if (!zone_watermark_ok(zone, order, mark,ac->classzone_idx, alloc_flags)) {int ret;/* Checked here to keep the fast path fast */BUILD_BUG_ON(ALLOC_NO_WATERMARKS < NR_WMARK);if (alloc_flags & ALLOC_NO_WATERMARKS)goto try_this_zone;if (IS_ENABLED(CONFIG_NUMA) &&!did_zlc_setup && nr_online_nodes > 1) {/** we do zlc_setup if there are multiple nodes* and before considering the first zone allowed* by the cpuset.*/allowednodes = zlc_setup(zonelist, alloc_flags);zlc_active = 1;did_zlc_setup = 1;}if (zone_reclaim_mode == 0 ||!zone_allows_reclaim(ac->preferred_zone, zone))goto this_zone_full;/** As we may have just activated ZLC, check if the first* eligible zone has failed zone_reclaim recently.*/if (IS_ENABLED(CONFIG_NUMA) && zlc_active &&!zlc_zone_worth_trying(zonelist, z, allowednodes))continue;ret = zone_reclaim(zone, gfp_mask, order);switch (ret) {case ZONE_RECLAIM_NOSCAN:/* did not scan */continue;case ZONE_RECLAIM_FULL:/* scanned but unreclaimable */continue;default:/* did we reclaim enough */if (zone_watermark_ok(zone, order, mark,ac->classzone_idx, alloc_flags))goto try_this_zone;/** Failed to reclaim enough to meet watermark.* Only mark the zone full if checking the min* watermark or if we failed to reclaim just* 1<<order pages or else the page allocator* fastpath will prematurely mark zones full* when the watermark is between the low and* min watermarks.*/if (((alloc_flags & ALLOC_WMARK_MASK) == ALLOC_WMARK_MIN) ||ret == ZONE_RECLAIM_SOME)goto this_zone_full;continue;}}try_this_zone:page = buffered_rmqueue(ac->preferred_zone, zone, order,gfp_mask, ac->migratetype);if (page) {if (prep_new_page(page, order, gfp_mask, alloc_flags))goto try_this_zone;return page;}
this_zone_full:if (IS_ENABLED(CONFIG_NUMA) && zlc_active)zlc_mark_zone_full(zonelist, z);}/**************************for_each_zone_zonelist_nodemask [End]*************************//** The first pass makes sure allocations are spread fairly within the* local node.  However, the local node might have free pages left* after the fairness batches are exhausted, and remote zones haven't* even been considered yet.  Try once more without fairness, and* include remote zones now, before entering the slowpath and waking* kswapd: prefer spilling to a remote zone over swapping locally.*/if (alloc_flags & ALLOC_FAIR) {alloc_flags &= ~ALLOC_FAIR;if (nr_fair_skipped) {zonelist_rescan = true;reset_alloc_batches(ac->preferred_zone);}if (nr_online_nodes > 1)zonelist_rescan = true;}if (unlikely(IS_ENABLED(CONFIG_NUMA) && zlc_active)) {/* Disable zlc cache for second zonelist scan */zlc_active = 0;zonelist_rescan = true;}if (zonelist_rescan)goto zonelist_scan;return NULL;
}

以上代码比较长,主要分两部分:

(1)for_each_zone_zonelist_nodemask{}结构中部分。

(2)页面分配完后的后续操作

(2-2-1)for_each_zone_zonelist_nodemask{}

for_each_zone_zonelist_nodemask本质是一个宏定义:

#define for_each_zone_zonelist_nodemask(zone, z, zlist, highidx, nodemask) \for (z = first_zones_zonelist(zlist, highidx, nodemask, &zone);	\zone;							\z = next_zones_zonelist(++z, highidx, nodemask),	\zone = zonelist_zone(z))			\
  • zone:迭代器中的当前zone
  • z:正在被迭代的zonelist->zone中的当前指针
  • zlist:正在迭代的zonelist
  • highidx:最高zone的zone索引
  • nodemask:分配器允许的nodemask

该宏定义功能是:充当一个迭代器,用于在给定zone索引或低于给定zone索引和节点掩码的zonelist中迭代有效的zone。

  • first_zones_zonelist()功能是:返回zonelist中允许的nodemask中最高zoneidx或低于最高zoneidx的第一个zoneref指针(注:zoneref结构中包含了一个zone和一个zoneidx)。

  • next_zones_zonelist功能是:返回位于或低于zonelist中最高zoneidx的下一个zone。

for_each_zone_zonelist_nodemask找到了zone,接下来会调用zone_watermark_ok()检查zone中的水位是否充足。

如果检测到zone中的水位充足,就调用buffered_rmqueue()函数从伙伴系统中分配物理页面。buffered_rmqueue()函数的功能是:从给定的zone中分配一个页面。注:当order为0时的分配将使用pcplist(什么是pcplist,容后续分析!)。

(2-2)重要函数2:(__alloc_pages_slowpath())

__alloc_pages_slowpath()函数较长,该函数是在get_page_from_freelist()尝试分配物理页面失败后才会调用。经过该函数处理后结果有两种情况:

​(1)情况1、重新分配物理页面成功,那么将返回对应的page。

​(2)情况2、页面分配失败,将调用warn_alloc_failed()函数提示物理页面分配失败,并将打印出:

%s: page allocation failure: order:%d

​ 类似信息。

三、分配掩码

(3-1)分配掩码宏定义

分配掩码是一个在linux内核进行内存分配时需要执行或传递的重要参数,用于控制分配器的页面分配行为和状态。其定义在文件(/include/linux/gfp.h)中:

#define ___GFP_DMA		0x01u
#define ___GFP_HIGHMEM		0x02u
#define ___GFP_DMA32		0x04u
#define ___GFP_MOVABLE		0x08u
#define ___GFP_WAIT		0x10u
#define ___GFP_HIGH		0x20u
#define ___GFP_IO		0x40u
#define ___GFP_FS		0x80u
#define ___GFP_COLD		0x100u
#define ___GFP_NOWARN		0x200u
#define ___GFP_REPEAT		0x400u
#define ___GFP_NOFAIL		0x800u
#define ___GFP_NORETRY		0x1000u
#define ___GFP_MEMALLOC		0x2000u
#define ___GFP_COMP		0x4000u
#define ___GFP_ZERO		0x8000u
#define ___GFP_NOMEMALLOC	0x10000u
#define ___GFP_HARDWALL		0x20000u
#define ___GFP_THISNODE		0x40000u
#define ___GFP_RECLAIMABLE	0x80000u
#define ___GFP_NOACCOUNT	0x100000u
#define ___GFP_NOTRACK		0x200000u
#define ___GFP_NO_KSWAPD	0x400000u
#define ___GFP_OTHER_NODE	0x800000u
#define ___GFP_WRITE		0x1000000u

以上宏定义在实际开发中,内核开发者们建议不要直接使用,而是将其组合着使用:

分配掩码在linux内核中分为两类:

(1)zone_modifiers:指定从哪个zone中分配页面。有以下宏定义选项(/include/linux/gfp.h):

#define __GFP_DMA	((__force gfp_t)___GFP_DMA)
#define __GFP_HIGHMEM	((__force gfp_t)___GFP_HIGHMEM)
#define __GFP_DMA32	((__force gfp_t)___GFP_DMA32)
#define __GFP_MOVABLE	((__force gfp_t)___GFP_MOVABLE)  /* Page is movable */
#define GFP_ZONEMASK	(__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE)

(2)action_modifiers:由分配掩码的最低4位来定义,分别是__GFP_DMA__GFP_HIGHMEM__GFP_DMA32__GFP_MOVABLE。有以下宏定义选项(/include/linux/gfp.h):

#define __GFP_WAIT	((__force gfp_t)___GFP_WAIT)	/* Can wait and reschedule? */
#define __GFP_HIGH	((__force gfp_t)___GFP_HIGH)	/* Should access emergency pools? */
#define __GFP_IO	((__force gfp_t)___GFP_IO)	/* Can start physical IO? */
#define __GFP_FS	((__force gfp_t)___GFP_FS)	/* Can call down to low-level FS? */
#define __GFP_COLD	((__force gfp_t)___GFP_COLD)	/* Cache-cold page required */
#define __GFP_NOWARN	((__force gfp_t)___GFP_NOWARN)	/* Suppress page allocation failure warning */
#define __GFP_REPEAT	((__force gfp_t)___GFP_REPEAT)	/* See above */
#define __GFP_NOFAIL	((__force gfp_t)___GFP_NOFAIL)	/* See above */
#define __GFP_NORETRY	((__force gfp_t)___GFP_NORETRY) /* See above */
#define __GFP_MEMALLOC	((__force gfp_t)___GFP_MEMALLOC)/* Allow access to emergency reserves */
#define __GFP_COMP	((__force gfp_t)___GFP_COMP)	/* Add compound page metadata */
#define __GFP_ZERO	((__force gfp_t)___GFP_ZERO)	/* Return zeroed page on success */
#define __GFP_NOMEMALLOC ((__force gfp_t)___GFP_NOMEMALLOC) /* Don't use emergency reserves.*/
#define __GFP_HARDWALL   ((__force gfp_t)___GFP_HARDWALL) /* Enforce hardwall cpuset memory allocs */
#define __GFP_THISNODE	((__force gfp_t)___GFP_THISNODE)/* No fallback, no policies */
#define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE) /* Page is reclaimable */
#define __GFP_NOACCOUNT	((__force gfp_t)___GFP_NOACCOUNT) /* Don't account to kmemcg */
#define __GFP_NOTRACK	((__force gfp_t)___GFP_NOTRACK)  /* Don't track with kmemcheck */#define __GFP_NO_KSWAPD	((__force gfp_t)___GFP_NO_KSWAPD)
#define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE) /* On behalf of other node */
#define __GFP_WRITE	((__force gfp_t)___GFP_WRITE)	/* Allocator intends to dirty page */
(3-2)宏定义组合

​ 宏定义组合就是将两个或多个分配掩码宏定义组合成一个宏定义,以便实现多个功能掩码标记。常用宏定义组合如下(/include/linux/gfp.h):

#define GFP_ATOMIC	(__GFP_HIGH)
#define GFP_NOIO	(__GFP_WAIT)
#define GFP_NOFS	(__GFP_WAIT | __GFP_IO)
#define GFP_KERNEL	(__GFP_WAIT | __GFP_IO | __GFP_FS)
#define GFP_TEMPORARY	(__GFP_WAIT | __GFP_IO | __GFP_FS | \__GFP_RECLAIMABLE)
#define GFP_USER	(__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL)
#define GFP_HIGHUSER	(GFP_USER | __GFP_HIGHMEM)
#define GFP_HIGHUSER_MOVABLE	(GFP_HIGHUSER | __GFP_MOVABLE)
#define GFP_IOFS	(__GFP_IO | __GFP_FS)
#define GFP_TRANSHUGE	(GFP_HIGHUSER_MOVABLE | __GFP_COMP | \__GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN | \__GFP_NO_KSWAPD)

(注:代码没贴完,具体可参考源码)

四、总结

linux分配物理页面的过程比较复杂,用一张图来总结一下:

在这里插入图片描述


http://chatgpt.dhexx.cn/article/3AIZSaHc.shtml

相关文章

深度讲解Linux内存管理和Linux进程调度-打通任督二脉

《穆赫兰道》与《内陆帝国》 我在多年的工程生涯中发现很多工程师碰到一个共性的问题&#xff1a;Linux工程师很多&#xff0c;甚至有很多有多年工作经验&#xff0c;但是对一些Linux内存管理和linux进程管理关键概念的理解非常模糊&#xff0c;比如不理解CPU、内存资源等的真正…

Linux内存管理机制

在Linux中经常发现空闲内存很少&#xff0c;似乎所有的内存都被系统占用了&#xff0c;表面感觉是内存不够用了&#xff0c;其实不然。这是Linux内存管理的一个优秀特性&#xff0c;主要特点是&#xff0c;无论物理内存有多大&#xff0c;Linux 都将其充份利用&#xff0c;将一…

关于linux内存管理

Linux的内存管理主要分为两部分&#xff1a;物理地址到虚拟地址的映射&#xff0c;内核内存分配管理&#xff08;主要基于slab&#xff09;。 物理地址到虚拟地址之间的映射 1、概念 物理地址(physical address) 用于内存芯片级的单元寻址&#xff0c;与处理器和CPU连接的地址…

深入理解Linux内存管理-之-目录导航

日期内核版本架构作者GitHubCSDN2016-08-31Linux-4.7X86 & armgatiemeLinuxDeviceDriversLinux内存管理 1 内存描述 CSDNGitHubLinux内存描述之概述–Linux内存管理(一)01-description/01-memoryLinux内存描述之内存节点node–Linux内存管理(二)01-description/02-nodeLin…

Linux内存管理(下)

Linux内存管理(下) 物理内存管理&#xff08;页管理&#xff09; Linux内核管理物理内存是通过分页机制实现的&#xff0c;它将整个内存划分成无数4k(在i386体系结构中)大小页&#xff0c;从而分配和回收内存的基本单位便是内存页了。利用分页管理有助于灵活分配内存地址&…

Linux中的内存管理机制

Linux中的内存管理机制 ​ 程序在运行时所有的数据结构的分配都是在堆和栈上进行的&#xff0c;而堆和栈都是建立在内存之上。内存作为现代计算机运行的核心&#xff0c;CPU可以直接访问的通用存储只有内存和处理器内置的寄存器&#xff0c;所有的代码都需要装载到内存之后才能…

Linux - 内存管理

【1】前言 内存管理是指软件运行时对计算机内存资源的分配和使用的技术。其最主要的目的是如何高效&#xff0c;快速的分配&#xff0c;并且在适当的时候释放和回收内存资源。 内存管理是操作系统很重要的一部分。作为一个后端开发来说&#xff0c;了解操作系统是如何进行内存…

Linux的内存管理

Linux的内存管理 Linux的内存管理是一个非常复杂的过程&#xff0c;主要分成两个大的部分&#xff1a;内核的内存管理和进程虚拟内存。内核的内存管理是Linux内存管理的核心&#xff0c;所以我们先对内核的内存管理进行简介。 一、物理内存模型 物理内存模型主要分为两种&…

Linux内存管理(上)

Linux内存管理(上) 摘要&#xff1a;本章首先以应用程序开发者的角度审视Linux的进程内存管理&#xff0c;在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存地使用方法。力求从外自内、水到渠成地引导网友分析Linux地内存管理与使用。在本章最后我们给出一个内存映射…

【纯干货】Linux内存管理(最透彻的一篇)

摘要&#xff1a;本章首先以应用程序开发者的角度审视Linux的进程内存管理&#xff0c;在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法。力求从外到内、水到渠成地引导网友分析Linux的内存管理与使用。在本章最后&#xff0c;我们给出一个内存映射的实例…

Linux内存管理方式

目录 前言 内存管理方式 分段式 分页式 段页式 虚拟地址如何映射到物理地址 缺页中断 内存交换 内存置换算法 前言 之前说过linux中的程序地址空间是使用的虚拟地址&#xff0c;虚拟地址和真实的物理地址有着某种特殊的映射关系&#xff08;MMU&#xff0c;全称Memory Ma…

一文讲透Linux内存管理

一、Linux内存管理概述 Linux内存管理是指对系统内存的分配、释放、映射、管理、交换、压缩等一系列操作的管理。在Linux中&#xff0c;内存被划分为多个区域&#xff0c;每个区域有不同的作用&#xff0c;包括内核空间、用户空间、缓存、交换分区等。Linux内存管理的目标是最…

Linux内存管理(一):内存管理概述

首先明确下面几个概念&#xff1a; 程序(Program)&#xff1a;一组指令的有序集合&#xff0c;是静态的实体。进程(Process)&#xff1a;执行程序后&#xff0c;操作系统将程序的可执行文件和它的相关依赖加载到内存中&#xff0c;得到的动态的实体称为进程。 程序和进程并不…

史上最全linux内存管理

Linux内存结构 Node 首先, 内存被划分为结点. 每个结点关联到系统中的一个处理器,内核中表示为pg_data_t的 实例. 系统中每个节点被链接到一个以NULL结尾的pgdat_list链表中<而其中的每个节点利用pg_data_tnode_next字段链接到下一节&#xff0e;而对于PC这种UMA结构的机…

一文掌握 Linux 内存管理

作者&#xff1a;dengxuanshi&#xff0c;腾讯 IEG 后台开发工程师 以下源代码来自 linux-5.10.3 内核代码&#xff0c;主要以 x86-32 为例。 Linux 内存管理是一个很复杂的“工程”&#xff0c;它不仅仅是对物理内存的管理&#xff0c;也涉及到虚拟内存管理、内存交换和内存回…

linux内存管理(一)-内存管理架构

文章目录 一、内存管理架构二、虚拟地址空间布局架构2.1内核地址空间布局2.2用户地址空间布局 三、物理内存体系架构3.1 正常内存3.2 设备内存四、内存结构五、内存模型六、虚拟地址和物理地址的转换七、页表八、内存映射原理分析 一、内存管理架构 内存管理子系统架构可以分为…

Linux内存管理(最透彻的一篇)

【转】Linux内存管理&#xff08;最透彻的一篇&#xff09; 摘要&#xff1a;本章首先以应用程序开发者的角度审视Linux的进程内存管理&#xff0c;在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法。力求从外到内、水到渠成地引导网友分析Linux的内存管…

Linux内存管理机制(最透彻的一篇)

摘要&#xff1a;本章首先以应用程序开发者的角度审视Linux的进程内存管理&#xff0c;在此基础上逐步深入到内核中讨论系统物理内存管理和内核内存的使用方法。力求从外到内、水到渠成地引导网友分析Linux的内存管理与使用。在本章最后&#xff0c;我们给出一个内存映射的实例…

概述 - Linux内存管理(一)

内存管理是从单板上电运行uboot启动引导linux并完成文件系统挂载&#xff08;文件系统管理Nandflash&#xff09;过程前两个环节都需要完成的重要工作&#xff0c;并且随着程序推进的内存管理也逐渐完善起来。如果一步到位直接编写一个非常完整的内存管理系统&#xff0c;这个过…

linux 内存管理

目录 1 Linux内存管理概述 1.1 内存的层次结构 1.2 虚拟内存概述 1.2.1 虚拟内存基本思想 1.2.2 进程虚拟地址空间 1.3 内核空间到物理空间的映射 1.3.1 内核空间的线性映射 1.3.2 内核镜像的物理存储 1.4 虚拟内存实现机制 2 进程用户空间管理 2.1 进程用户空间布局…