Linux内存管理宏观篇(四)物理内存:物理内存管理区

简介: Linux内存管理宏观篇(四)物理内存:物理内存管理区

前言

前面我们了解了物理页面,知道物理页面的管理结构struct page的内容。

这里来看看物理内存的分区。

我们知道32位对于4GB,然后这个4GB分成了1GB的内核和3GB的用户。

1G的内核地址空间可访问全部的物理内存地址,3G的用户地址空间访问最大3G的物理内存地址。

因此在内核部分线性映射,肯定是无法实现的。怎么解决呢?

1、内核内存管理区

1GB的内核内存是分为两个部分,一部分是线性映射区域,一部分是高端内存(这里就是上一篇的疑惑点,这就解开了)。

一般0-768MB是线性的,剩下的可以映射到用户的内存区域,以及映射一些device。

线性的区域:ZONE_NORMAL
高端内存区域:ZONE_HGHMEM

这是因为32位只能最大映射到4GB,但是现在都是64位,这完全是够够的,那么64位的时候就不需要这个区域。

同时还有个区域。

DMA操作:ZONE_DMA

这个区域是因为ISA设备就不能在整个32位的地址空间中执行DMA操作,因为ISA设备只能访问物理内存的前16MB,所以在x86体系结构中会有一项ZONE_DMA的管理区域。

但是ARM中没有。

因此对于ARM32你需要了解两个区:

线性的区域:ZONE_NORMAL
高端内存区域:ZONE_HGHMEM

对于ARM64那么很明显就只需要一个区

线性的区域:ZONE_NORMAL

用户内存一年一一对应,因此无需多说,MMU也是如此。内核地址要通过MMU吗?这个问题留着,期待你的答案。我真不知道。

2、内存管理区描述符

对于这个内存管理区,内核也有个数据结构来管理 struct zone。

(这也是C语言面向对象的一种思想)

定义在include/linux/mmzone.h文件中。struct zone数据结构的主要成员如下。

[include/linux/mmzone.h]
struct zone {
  /* 读敏感域 */
  unsigned long watermark[NR_WMARK];
  long lowmem_reserve[MAX_NR_ZONES];
  struct pglist_data  *zone_pgdat;
  struct per_cpu_pageset __percpu *pageset;
  unsigned long     zone_start_pfn;
  unsigned long     managed_pages;
  unsigned long     spanned_pages;
  unsigned long     present_pages;
  const char     *name;
  /* 写敏感域 */
  ZONE_PADDING(_pad1_)struct free_area   free_area[MAX_ORDER];
  unsigned long     flags;
  spinlock_t     lock;
  ZONE_PADDING(_pad2_)spinlock_t     lru_lock;
  struct lruvec     lruvec;
  /* 内存管理区的统计信息 */
  ZONE_PADDING(_pad3_)atomic_long_t     vm_stat[NR_VM_ZONE_STAT_ITEMS];
  } ____cacheline_internodealigned_in_smp;

首先,struct zone是经常会被访问到的,因此这个数据结构要求以L1 Cache对齐,见____cacheline_internodealigned_in_smp属性。

struct zone总体来说可以分成以下3个部分。读敏感区域。写敏感区域。统计计数。

这里的ZONE_PADDING()是让zone->lock和zone->lru_lock这两个很热门的锁分布在不同的缓存行(cache line)中。

这里采用ZONE_PADDING()让其后面的变量与L1缓存行对齐,以提高该字段的并发访问性能,避免发生缓存伪共享(Cache False Sharing)。

另外,一个内存节点最多也就几个内存管理区,因此内存管理区数据结构不需要像struct page一样对数据结构的大小特别敏感,这里可以为了性能而浪费空间。

在内存管理开发过程中,内核开发者逐步发现有一些自旋锁竞争得非常厉害,很难获取。像 zone->lock 和zone->lru_lock 这两个锁有时需要同时获取,会导致比较严重的高速缓存伪共享问题,保证它们使用不同的缓存行是内核常用的一种优化技巧。

watermark:每个内存管理区在系统启动时会计算出 3 个水位值,分别是WMARK_MIN、WMARK_LOW 和 WMARK_HIGH 水位,这在页面分配器和kswapd页面回收中会用到。

lowmem_reserve:内存管理区中预留的内存。

zone_pgdat:指向内存节点。

pageset:用于维护Per-CPU上的一系列页面,以减少自旋锁的争用。

zone_start_pfn:内存管理区中开始页面的页帧号。

managed_pages:内存管理区中被伙伴系统管理的页面数量。

spanned_pages:内存管理区包含的页面数量。

present_pages:内存管理区里实际管理的页面数量。对一些体系结构来说,其值和spanned_pages相等。

free_area:管理空闲区域的数组,包含管理链表等。

lock:并行访问时用于对内存管理区保护的自旋锁。注意该锁是保护

struct zone数据结构本身,而不是内存管理区所描述的内存地址空间。

lru_lock:用于对内存管理区中LRU链表并发访问时进行保护的自旋锁。

lruvec:LRU链表集合。

vm_stat:内存管理区计数。

对于这个部分,参数要等你使用的时候再加深映像。关于ZONE_PADDING()和缓存行那些,我也暂时讲不清楚,等我改天学习一下,写个内存管理番外篇。

3、辅助操作函数

Linux 内核提供了几个常用的内存管理区的辅助操作函数,它们定义在include/linux/mmzone.h文件中。

#define for_each_zone(zone)          \
for (zone = (first_online_pgdat())->node_zones; \
zone;          \
zone = next_zone(zone))
static inline int is_highmem(struct zone *zone);
#define zone_idx(zone)    ((zone) - (zone)->zone_pgdat->node_zones)

其中,for_each_zone()用来遍历系统中所有的内存管理区;

(这点代码有点奇怪)

is_highmem()函数用来检测内存管理区是否属于ZONE_HIGHMEM;

zone_idx()宏用来返回当前zone所在的内存节点的编号。

说明这个zone挺多的,内存中就是以这个位更粗的粒度去管理。

4、小结

上一章知道了物理页面,这一章紧接着学习了内存管理区,其实内存管理区是更大的概念。后面对于这个zone,也整个番外篇,好好聊聊内存管理中的zone到底是什么?

这里简单说一下,页相对于是要具体点,zone就是根据内存是不同功能或者权限什么的,把内存分成了不同的zone,然后进行统一管理。是体现在对内存的管控,页是对内存的分配。当然zone也是分配,是根据功能等进行分配的。

5、待解问题

内核地址映射需要MMU吗?

下一章就来聊聊对于物理页面的释放和分配,少爷先休息会。

参考资料:

《奔跑吧 Linux内核》

目录
相关文章
|
23天前
|
安全 Linux Shell
Linux上执行内存中的脚本和程序
【9月更文挑战第3天】在 Linux 系统中,可以通过多种方式执行内存中的脚本和程序:一是使用 `eval` 命令直接执行内存中的脚本内容;二是利用管道将脚本内容传递给 `bash` 解释器执行;三是将编译好的程序复制到 `/dev/shm` 并执行。这些方法虽便捷,但也需谨慎操作以避免安全风险。
|
1天前
|
Java
在 ArkTS 中,如何有效地进行内存管理和避免内存泄漏?
【9月更文挑战第25天】在ArkTS中,有效进行内存管理并避免内存泄漏的方法包括:及时释放不再使用的资源,如关闭监听器和清理定时器;避免循环引用,通过弱引用打破循环;合理使用单例模式,确保单例对象正确释放;及时处理不再使用的页面和组件,在卸载时清理相关资源。
|
19天前
|
监控 Java 大数据
【Java内存管理新突破】JDK 22:细粒度内存管理API,精准控制每一块内存!
【9月更文挑战第9天】虽然目前JDK 22的确切内容尚未公布,但我们可以根据Java语言的发展趋势和社区的需求,预测细粒度内存管理API可能成为未来Java内存管理领域的新突破。这套API将为开发者提供前所未有的内存控制能力,助力Java应用在更多领域发挥更大作用。我们期待JDK 22的发布,期待Java语言在内存管理领域的持续创新和发展。
|
19天前
|
存储 并行计算 算法
CUDA统一内存:简化GPU编程的内存管理
在GPU编程中,内存管理是关键挑战之一。NVIDIA CUDA 6.0引入了统一内存,简化了CPU与GPU之间的数据传输。统一内存允许在单个地址空间内分配可被两者访问的内存,自动迁移数据,从而简化内存管理、提高性能并增强代码可扩展性。本文将详细介绍统一内存的工作原理、优势及其使用方法,帮助开发者更高效地开发CUDA应用程序。
|
1月前
|
存储 Linux 索引
深入理解Linux虚拟内存管理(九)(中)
深入理解Linux虚拟内存管理(九)
22 2
|
1月前
|
机器学习/深度学习 消息中间件 Unix
深入理解Linux虚拟内存管理(九)(下)
深入理解Linux虚拟内存管理(九)
19 1
|
14天前
|
监控 算法 数据可视化
深入解析Android应用开发中的高效内存管理策略在移动应用开发领域,Android平台因其开放性和灵活性备受开发者青睐。然而,随之而来的是内存管理的复杂性,这对开发者提出了更高的要求。高效的内存管理不仅能够提升应用的性能,还能有效避免因内存泄漏导致的应用崩溃。本文将探讨Android应用开发中的内存管理问题,并提供一系列实用的优化策略,帮助开发者打造更稳定、更高效的应用。
在Android开发中,内存管理是一个绕不开的话题。良好的内存管理机制不仅可以提高应用的运行效率,还能有效预防内存泄漏和过度消耗,从而延长电池寿命并提升用户体验。本文从Android内存管理的基本原理出发,详细讨论了几种常见的内存管理技巧,包括内存泄漏的检测与修复、内存分配与回收的优化方法,以及如何通过合理的编程习惯减少内存开销。通过对这些内容的阐述,旨在为Android开发者提供一套系统化的内存优化指南,助力开发出更加流畅稳定的应用。
31 0
|
26天前
|
Linux Shell 虚拟化
使用LiME收集主机物理内存的内容时发生宕机
使用LiME收集主机物理内存的内容时发生宕机
|
26天前
crash —— 获取物理内存布局信息
crash —— 获取物理内存布局信息
|
30天前
|
缓存 Linux 调度
Linux服务器如何查看CPU占用率、内存占用、带宽占用
Linux服务器如何查看CPU占用率、内存占用、带宽占用
125 0