底层开发必知的三个内存结构概念

简介: 底层开发必知的三个内存结构概念

Linux中内存管理子系统使用节点(node)、区域(zone)和页(page)三级结构描述物理内存。

内存节点

内存节点分两种情况:UMANUMA

从管理内存的方法上区分,计算机可以分为两种类型:UMANUMA

UMA:一致性内存访问,uniform memory access

NUMA:非一致性内存访问,non-uniform memory access

两种类型示意图:

UMA来说,每一个CPU 访问的都是同一块内存,因此各CPU对内存的访问不存在性能差异

NUMA来说,各内存和各CPU通过总线连在一起,每个CPU都有一个本地内存,访问速度快,CPU也可以访问其他CPU的本地内存,但速度稍慢

Linux为了统一这两种平台,在内存组织中,将最高层次定义为内存节点.

可以看到,图中UMA只有一个内存节点,而NUMA有两个内存节点。

实际上,UMA其实是NUMA的一个特例,所以内核可以将内存都看做NUMA类型的。

区域

每个内存节点都划分为多个区,Linux内核中定义了以下几个区:

include/linux/mmzone.h

enum zone_type{
#ifdef CONFIG_ZONE_DMA
 ZONE_DMA,
#endif
#ifdefi CONFIG_ZONE_DMA32
 ZONE_DMA32,
#endif
 ZONE_NORMAL,
#ifdef CONFIG_HIGHMEM
 ZONE_HIGHMEM,
#endif
 ZONE_MOVABLE,
#ifdef CONFIG_ZONE_DEVICE
 ZONE_DEVICE,
#endif
 __MAX_NR_ZONES
};

ZONE_DMA

DMA是“Direct Memory Access”的缩写,直接内存访问。

该区域用于ISA设备的DMA操作,范围是0-16MB。

如果有些设备不能直接访问所有内存,则需要使用DMA区域。例如旧的工业标准体系结构(Industry Standard Architecture, ISA)总线只能直接访问16MB以下的内存。

只适用于Intel x86架构,ARM架构没有这个内存管理区。

ZONE_DMA32

在64位的系统上使用32位地址寻址的适合DMA操作的内存区。

例如在AMD64系统上,该区域为低4GB的空间。在32位系统上,本区域通常是空的。

ZONE_NORMAL

常规内存区,指的是可以直接映射到内核空间的内存。

也常称为“普通区域”“直接映射区域”“线性映射区域”。

所谓线性映射就是物理地址和映射后的虚拟地址存在一种简单的关系,即虚拟地址=物理地址+固定偏移

在32位系统上,内核空间和用户空间按1:3划分,那么这个固定偏移就是:0xC0000000 - 物理内存起始地址

既然存在一种线性关系,那还需要使用页表对物理地址和虚拟地址做映射吗?

不同处理器架构实现不一样,ARM需要使用页表映射,MIPS则不需要。

ZONE_HIGHMEM

高端内存区,32位时代的产物。在32位系统上,指的是高于896M的物理内存。

32位系统中,内核和用户地址空间按1:3划分,内核地址空间只有1GB,所以不能把1GB以上的内存直接映射到内核地址空间,因此就把不能直接映射的内存划分到了高端内存区。

要将高于896MB的物理内存映射在内核空间的话,需要通过单独的映射来完成,并且这类映射不能保证物理地址和虚拟地址之间存在固定的对应关系(例如ZONE_NORMAL的固定偏移)。

ZONE_DMA、ZONE_DMA32、ZONE_NORMAL通常都统称为低端内存区。

64位系统中没有这个区域,即没有高端内存。因为64系统的内核虚拟地址空间非常大,不再需要高端内存区域。

ZONE_MOVABLE

一个伪内存区,用来防止内存碎片。

ZONE_DEVICE

为支持持久内存(persistent memory)热拔插增加的内存区域

站在处理器的角度来看,管理物理内存的最小单位是页面。

现在的处理器都采用分页机制来管理内存,在处理器内部有一个MMU硬件,它会处理虚拟内存到物理内存的映射,也就是做页表的翻译工作。

Linux内核中使用一个page数据结构来描述一个物理页面。

页的大小通常是4KB,但有个的架构的处理器可以支持大于4KB的页,例如8KB16KB或者64KB的页。

目前Linux内核默认使用4KB的页面。

所以,Linux内核的用三级结构来管理物理内存,简言之就是内存首先划分成若干个大的节点,每个节点又包含若干个区,每个区有包含若干页。Linux内核按页管理内存,最基本的内存分配和释放都是按页进行的。

end

往期推荐

直到我干了底层开发,才知道不写业务代码有多爽

你解决bug的能力,暴露了你的水平

入职Linux驱动工程师后,我才知道的真相......

很底层的性能优化:让CPU更快地执行你的代码

薪资倒挂,大家都沉默了...

机遇:我是如何走向Linux驱动的...

当我用几道题考了一遍做Linux驱动的同事......

相关文章
|
24天前
|
传感器 人工智能 物联网
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发
C 语言在计算机科学中尤其在硬件交互方面占据重要地位。本文探讨了 C 语言与硬件交互的主要方法,包括直接访问硬件寄存器、中断处理、I/O 端口操作、内存映射 I/O 和设备驱动程序开发,以及面临的挑战和未来趋势,旨在帮助读者深入了解并掌握这些关键技术。
42 6
|
28天前
|
Java
JVM运行时数据区(内存结构)
1)虚拟机栈:每次调用方法都会在虚拟机栈中产生一个栈帧,每个栈帧中都有方法的参数、局部变量、方法出口等信息,方法执行完毕后释放栈帧 (2)本地方法栈:为native修饰的本地方法提供的空间,在HotSpot中与虚拟机合二为一 (3)程序计数器:保存指令执行的地址,方便线程切回后能继续执行代码
21 3
|
2月前
|
存储 算法 Java
聊聊jvm的内存结构, 以及各种结构的作用
【10月更文挑战第27天】JVM(Java虚拟机)的内存结构主要包括程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和运行时常量池。各部分协同工作,为Java程序提供高效稳定的内存管理和运行环境,确保程序的正常执行、数据存储和资源利用。
59 10
|
3月前
|
监控 算法 Java
深入理解Java中的垃圾回收机制在Java编程中,垃圾回收(Garbage Collection, GC)是一个核心概念,它自动管理内存,帮助开发者避免内存泄漏和溢出问题。本文将探讨Java中的垃圾回收机制,包括其基本原理、不同类型的垃圾收集器以及如何调优垃圾回收性能。通过深入浅出的方式,让读者对Java的垃圾回收有一个全面的认识。
本文详细介绍了Java中的垃圾回收机制,从基本原理到不同类型垃圾收集器的工作原理,再到实际调优策略。通过通俗易懂的语言和条理清晰的解释,帮助读者更好地理解和应用Java的垃圾回收技术,从而编写出更高效、稳定的Java应用程序。
|
3月前
|
存储 运维
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
|
4月前
|
存储 程序员 C++
内存管理概念 (二)
内存管理概念 (二)
77 1
|
4月前
|
Swift iOS开发
iOS开发-属性的内存管理
【8月更文挑战第12天】在iOS开发中,属性的内存管理至关重要,直接影响应用性能与稳定性。主要策略包括:`strong`(强引用),不维持对象生命期,可用于解除循环引用;`assign`(赋值),适用于基本数据类型及非指针对象属性;`copy`,复制对象而非引用,确保对象不变性。iOS采用引用计数管理内存,ARC(自动引用计数)自动处理引用增减,简化开发。为避免循环引用,可利用弱引用或Swift中的`[weak self]`。最佳实践包括:选择恰当的内存管理策略、减少不必要的强引用、及时释放不再使用的对象、注意block内存管理,并使用Xcode工具进行内存分析。
|
4月前
|
存储 安全 Java
JVM内存结构
这篇文章详细介绍了Java虚拟机(JVM)的内存结构,包括类的加载过程、类加载器的双亲委派机制、沙箱安全机制、程序计数器、Java栈、Java堆、本地方法和本地方法栈等关键组件及其作用。
JVM内存结构
|
5月前
|
Java 运维
开发与运维内存问题之文件句柄泄漏如何解决
开发与运维内存问题之文件句柄泄漏如何解决
81 3
|
5月前
|
缓存 Java Linux
开发与运维内存问题之线上遇到故障,使用jstat命令发现Old区持续增长如何解决
开发与运维内存问题之线上遇到故障,使用jstat命令发现Old区持续增长如何解决
53 2