内存分配-页(page)

本文深入探讨了Linux内核中内存管理的基础单位——页(Page),包括struct page结构及其字段,以及区分不同用途的区(Zone)。通过alloc_pages函数和_alloc_pages_nodemask的具体分析,揭示了内核如何分配和获取物理内存页。同时,讨论了内存分配掩码(gfp_mask)的重要角色,它涉及内存管理区修饰符、移动修饰符、水位修饰符等多个方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.页  

 内核把物理页作为内存管理的基本单元,并用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;
}

   flag表示页的状态

  _count表示引用次数,为负值时表示空闲,可以调用page_count查询_count值,返回0表示空闲

  virtual表示页的虚拟地址。高端内存中,动态映射时,该值为NULL。

  lru 表示页面回收的LRU链表算法

2.区

    Linux把系统的页划分为区,形成不同的内存池,可以根据用途进行分配。具体的分区要看不同的硬件体系架构,常用的分区为:ZONE_NORMAL,ZONE_HIGHMEM,ZONE_DMA;每个区都用struct zone表示:
 

struct zone {

	unsigned long watermark[NR_WMARK];
	unsigned long percpu_drift_mark;
	unsigned long		lowmem_reserve[MAX_NR_ZONES];
	unsigned long		dirty_balance_reserve;
#ifdef CONFIG_NUMA
	int node;
	unsigned long		min_unmapped_pages;
	unsigned long		min_slab_pages;
#endif
	struct per_cpu_pageset __percpu *pageset;
	spinlock_t		lock;
	int                     all_unreclaimable; /* All pages pinned */
#ifdef CONFIG_MEMORY_HOTPLUG
	/* see spanned/present_pages for more description */
	seqlock_t		span_seqlock;
#endif
	struct free_area	free_area[MAX_ORDER];

#ifndef CONFIG_SPARSEMEM
	unsigned long		*pageblock_flags;
#endif /* CONFIG_SPARSEMEM */

#ifdef CONFIG_COMPACTION
	unsigned int		compact_considered;
	unsigned int		compact_defer_shift;
	int			compact_order_failed;
#endif

	ZONE_PADDING(_pad1_)
	spinlock_t		lru_lock;
	struct lruvec		lruvec;

	struct zone_reclaim_stat reclaim_stat;

	unsigned long		pages_scanned;	   /* since last reclaim */
	unsigned long		flags;		   /* zone flags, see below */

	atomic_long_t		vm_stat[NR_VM_ZONE_STAT_ITEMS];
	unsigned int inactive_ratio;
	ZONE_PADDING(_pad2_)
	wait_queue_head_t	* wait_table;
	unsigned long		wait_table_hash_nr_entries;
	unsigned long		wait_table_bits;

	struct pglist_data	*zone_pgdat;
	unsigned long		zone_start_pfn;

	unsigned long		spanned_pages;	/* total size, including holes */
	unsigned long		present_pages;	/* amount of memory (excluding holes) */

	const char		*name;
} ____cacheline_internodealigned_in_smp;

    其中watermark数组持有该区的最小值、最低和最高水位,分别为:WMARK_MIN,WMARK_LOW和WMARK_HIGH

   3.获得页

   内核提供了请求内存的底层机制。核心函数是:alloc_pages(gfp_mask, order)

#define alloc_pages(gfp_mask, order) \
		alloc_pages_node(numa_node_id(), gfp_mask, order)

static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
						unsigned int order)
{
	/* Unknown node is current node */
	if (nid < 0)
		nid = numa_node_id();

	return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask));
}

__alloc_pages(gfp_t gfp_mask, unsigned int order,
		struct zonelist *zonelist)
{
	return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL);
}

      alloc_pages最终调用的是_alloc_pages_nodemask,后面会仔细分析。alloc_pages返回的是page结构体,可以用page_address函数转换成对应的逻辑地址。

#define page_address(page) ((page)->virtual)

    如果无需用到struct page结构体,可以直接调用_get_free_pages

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值