本文共 3508 字,大约阅读时间需要 11 分钟。
鸿蒙内核的内存管理机制涉及多个复杂概念,尤其是从进程和线程的角度来看,内存管理的实现细节尤为重要。本文将从进程和线程的创建视角,深入剖析鸿蒙内核内存管理的运作机制。
进程使用的内存由LosVmSpace
结构体描述,内部包含多个虚拟存储区域(region)。Linux内核从2.4.10版本起,采用红黑树(regionRbTree)组织虚拟区,提升操作效率。LosVmSpace
还维护物理地址映射相关的信息,确保进程能够在用户空间和内核空间之间切换。
typedef struct LosVmSpace { LOS_DL_LIST node; /* vm space dl list */ LOS_DL_LIST regions; /* region dl list */ LosRbTree regionRbTree;/* region红黑树根 */ LosMux regionMux; /* region list_mutex */ VADDR_T base; /* vm space base address */ UINT32 size; /* vm space size */ VADDR_T heapBase; /* heap base address */ VADDR_T heapNow; /* heap base address */ LosVmMapRegion *heap; /* heap region */ VADDR_T mapBase; /* mapping area base */ UINT32 mapSize; /* mapping area size */ LosArchMmu archMmu; /* vm mapping物理内存 */ #ifndef LOSCFG_DRIVERS_TZDRIVER VADDR_T codeStart; /* user process code area start */ VADDR_T codeEnd; /* user process code area end */ #endif} LosVmSpace;
LosVmSpace
将内存划分为多个虚拟存储区域,主要分为以下几种类型:
/dev/shm
的临时存储。所有用户程序的父进程都是由init
进程发fork而来的。本文将重点分析init
进程的内存初始化过程,以及如何为进程分配初始栈和堆空间。
在进程创建时,首先需要分配栈空间和堆空间。栈用于存储函数调用信息(如返回地址、局部变量等),而堆则用于动态内存分配。
static Void* OsUserInitStackAlloc(UINT32 processID, UINT32* size) { LosVmMapRegion* region = NULL; LosProcessCB* processCB = OS_PCB_FROM_PID(processID); UINT32 stackSize = ALIGN(OS_USER_TASK_STACK_SIZE, PAGE_SIZE); region = LOS_RegionAlloc(processCB->vmSpace, 0, stackSize, VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_WRITE, 0); if (region == NULL) { return NULL; } LOS_SetRegionTypeAnon(region); region->regionFlags |= VM_MAP_REGION_FLAG_STACK; *size = stackSize; return (Void*)(UINTPTR)region->range.base;}
typedef struct VmMapRegion { LosRbNode rbNode; /* 区域红黑树节点 */ LosVmSpace *space; /* 所属虚拟内存空间 */ LOS_DL_LIST node; /* 区域双向链表节点 */ VmMapRange range; /* 区域地址范围 */ VM_OFFSET_T pgOff; /* 区域相对于文件的页移位 */ UINT32 regionFlags; /* 区域标志 */ UINT32 shmid; /* 区域的共享内存ID */ UINT8 protectFlags; /* 保护标志 */ UINT8 forkFlags; /* 复制模式 */ UINT8 regionType; /* 区域类型:anon,file,dev */ union { struct VmRegionFile { /* 跟踪信息,省略详细内容 */ }; struct VmRegionAnon { /* 匿名内存结构,省略详细内容 */ }; struct VmRegionDev { /* 设备内存结构,省略详细内容 */ }; } unTypeData;} VmMapRegion;
在用户进程初始化时,首先需要加载代码和数据段。这些段由内核映射到虚拟地址空间中,确保用户程序可以正常运行。具体来说,Los_VaddrToPaddrMmap
函数负责将用户虚拟地址映射到物理地址。
最后,通过OS_UserInitProcessStart
函数启动新的用户任务,任务入口函数指向应用程序的main
函数。
逻辑地址是程序使用的内存 references,通常是段中的偏移地址。例如,在C语言中使用指针时,指针的值即为逻辑地址。逻辑地址在保护模式下与物理地址不同,需要通过页表和段表进行转换。
线性地址是逻辑地址与物理地址之间的中间层。在分页或分段机制启用时,线性地址会被转换为物理地址。例如,在无分页机制的情况下,线性地址就是物理地址。
物理地址是CPU访问内存的最终地址,与地址总线相连接。无论是单个字节还是多个字节,物理地址都直接对应外存器的物理位置。
虚拟内存是操作系统为程序提供的逻辑内存扩展功能,使得程序可以运行于远超系统物理内存的虚拟空间中。通过交换、分页和页面技术,虚拟内存管理内存资源极为复杂。
从进程和线程的视角分析鸿蒙内核的内存管理机制,核心是理解如何为进程分配和管理内存区域。本文从初始进程创建、内存分配到栈和堆、以及地址转换等方面展开讨论,为深入理解鸿蒙内核内存管理奠定基础。
转载地址:http://rkryk.baihongyu.com/