linux内存管理(一)源码解析之内核虚拟内存布局

本文kernel代码分析基于以下
1.linux-4.14.159
2.64bit代码处理逻辑

linux内存管理非常复杂及庞大,这节我们看下内核虚拟内存布局,理解内核内存布局对认识内存管理至关重要,我们从源码来进行解析,这样通过理解记忆的话比较牢固。

在linux系统中,内核的虚拟地址空间对所有进程共享的,然而每一个进程存在自己的用户虚拟地址空间和共享的内核虚拟地址空间,此节我们仅研究内核虚拟地址空间。

arm v8架构可以支持32~48位的物理寻址,最大可以寻找256TB的物理地址空间,64位支持64位寻址,为什么最大48位呢?因为48位对目前的应用已经够用,就无需进行64位的物理寻址,太大势必会增加硬件的设计复杂度。

针对arm64的硬件体系结构,如果page大小位4KB,使用3级或4级转换表,内核虚拟地址空间支持39位(512G)或48位(256TB)的寻址空间。

先看地址空间大小:

arch\arm64\include\asm\memory.h
#define VA_BITS			(CONFIG_ARM64_VA_BITS)	

//.config中查看CONFIG_ARM64_VA_BITS=39,

VA_BITS虚拟地址宽度,最大支持48位,不同系统看具体配置的值。如我这边config中配置的时39位,即64位系统配置为39位,值为0x7F FFFF FFFF,这个换算过来即位512G。

0x0000_0000_0000_0000~0x0000_007f_ffff_ffff 512GB user
0xffff_ff80_0000_0000~0xffff_ffff_ffff_ffff 512GB kernel

如之前阐述,linux在arm架构上虚拟地址分位用户虚拟地址空间和内核虚拟地址空间这两个空间,如上每个空间支持512GB寻址。

内核虚拟地址空间起始地址

#define VA_START		(UL(0xffffffffffffffff) - \
	(UL(1) << VA_BITS) + 1)

//展开0xFFFF_FFFF_FFFF_FFFF-0x0000_0080_0000_0000+1=0xFFFF_FF80_0000_ 0000
//也就是说kernel虚拟地址空间起始地址为0xFFFF_FF80_0000_ 0000

内核线性映射的起始地址

#define PAGE_OFFSET		(UL(0xffffffffffffffff) - \
	(UL(1) << (VA_BITS - 1)) + 1)

///计算下来为0xFFFF_FFC0_0000_ 0000

KASAN和MODULE区域
KASAN(KernelAddressSANitizer)是一个动态检测内存错误的工具,主要解决use-after-free和out-of-bounds问题,其原理是利用额外的内存标记可用内存的状态。这部分额外的内存被称作shadow memory(影子区),KASAN将1/8的内存用作shadow memory,详细的内容请百度了解。

MODULE:是内核模块使用的虚拟地址空间,其大小为128MB

/*KIMAGE_VADDR - the virtual address of the start of the kernel image*/
#define KIMAGE_VADDR (MODULES_END)
#define MODULES_END (MODULES_VADDR + MODULES_VSIZE) 
#define MODULES_VADDR (VA_START + KASAN_SHADOW_SIZE)
// 0xFFFF_FF90 0000 0000
#define MODULES_VSIZE (SZ_128M)

#ifdef CONFIG_KASAN
#define KASAN_SHADOW_SIZE (UL(1) << (VA_BITS - 3)) 
// 0x10_0000_0000 :64G
#define KASAN_THREAD_SHIFT 1
#else

我们可以看到MODULES_VADDR ,等于VA_START + KASAN_SHADOW_SIZE,而KASAN_SHADOW_SIZE计算下来为64G,
因此MODULES_VADDR 地址为 0xFFFF_FF90 0000 0000
MODULES_END 地址为0xFFFF_FF90_0800_0000

///已确认的内存布局如下:
0xFFFF_FF80_0000_0000 ------ VA_START 

Kasan大小64G  

0xFFFF_FF90_0000_0000 ------ MODULES_VADDR 

MODULE大小为128M

0xFFFF_FF90_0800_0000 ------ MODULES_END 

64G为512G的1/8,因此符合kasan的定义。

再看VMALLOC区域
此区域为vmalloc函数使用的虚拟地址空间,注意因为linux kernel更新很快,笔者研究的代码kernel image映射区域已经从从原来的线性映射区域搬移到了VMALLOC区域

#define PUD_SIZE (_AC(1, UL) << PUD_SHIFT) 

#if CONFIG_PGTABLE_LEVELS > 3
#define PUD_SHIFT		ARM64_HW_PGTABLE_LEVEL_SHIFT(1)
#endif

page_SHIFT=12 //(4K)
#define SZ_64K				0x00010000

#define ARM64_HW_PGTABLE_L
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Linux虚拟内存管理是操作系统中非常重要的一个部分,下面我将以图形化的方式带您深入理解。 首先,让我们来看一张图示,展示了Linux虚拟内存管理的关键组成部分。在Linux中,虚拟内存主要由三个部分组成:用户空间、内核空间和交换区。 用户空间是应用程序运行的空间,程序的逻辑代码和数据都存放在这里。用户空间的大小是由操作系统分配的,一般是32位或64位。 内核空间是操作系统的核心部分,包含了操作系统的核心代码和数据。内核空间是操作系统独占的,应用程序无法直接访问。 交换区是用于辅助内存管理的一块磁盘空间。当内存不足时,操作系统会将部分内存中的数据写入交换区,从而腾出更多的内存空间。 接下来,我们来详细了解一下虚拟内存管理的过程。当应用程序需要访问内存中的某个数据时,首先会发起一个内存访问请求。操作系统会通过页表将虚拟地址转换为物理地址,从而确定在实际的物理内存中的位置。如果所需的数据已经在物理内存中,则应用程序可以直接访问,否则操作系统就会从交换区中将数据加载到物理内存中,并更新页表。 虚拟内存管理还包括页面置换算法,用于在内存不足时选择哪些页面从内存中换出到交换区中。常见的页面置换算法有最近最少使用(LRU)和先进先出(FIFO)等。 使用虚拟内存管理技术,操作系统可以为每个应用程序提供独立的内存空间,保证了应用程序的隔离性和安全性。虚拟内存管理还可以提供更大的内存空间,使得应用程序能够处理更大规模的数据。 总的来说,Linux虚拟内存管理是一套复杂的技术体系,通过将虚拟地址转换为物理地址,实现了对内存的合理管理和优化。通过使用交换区和页面置换算法,操作系统可以在内存不足时保证系统的正常运行。希望以上图文说明能帮助您更深入地理解Linux虚拟内存管理

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值