以前自己跟着内核内存管理的一些宏定义画过内存分布图
比如VMALLOC_START, VMALLOC_END, FIXADDR_START等等
一直以为这些值在实际内核中多多少少会有误差,没想到前几天看了一下
居然完全吻合。
来试着计算一下Vmalloc的总大小,为了便于计算我们认为1G的内核空间从0地址开始。
首先我的物理内存超过了896M,因此high_memory就是896M
其上是8M的空洞用于捕捉越界的内存访问,于是VMALLOC_START在896M+8M = 904M
下面再来计算VMALLOC_END。
最顶上是一个内存空洞,然后是固定映射的区域,这个区域的分布可以参考下面这个枚举
enum fixed_addresses {
FIX_HOLE,
FIX_VDSO,
FIX_DBGP_BASE,
FIX_EARLYCON_MEM_BASE,
#ifdef CONFIG_X86_LOCAL_APIC
FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
#endif
#ifdef CONFIG_X86_IO_APIC
FIX_IO_APIC_BASE_0,
FIX_IO_APIC_BASE_END = FIX_IO_APIC_BASE_0 + MAX_IO_APICS-1,
#endif
#ifdef CONFIG_X86_VISWS_APIC
FIX_CO_CPU, /* Cobalt timer */
FIX_CO_APIC, /* Cobalt APIC Redirection Table */
FIX_LI_PCIA, /* Lithium PCI Bridge A */
FIX_LI_PCIB, /* Lithium PCI Bridge B */
#endif
#ifdef CONFIG_X86_F00F_BUG
FIX_F00F_IDT, /* Virtual mapping for IDT */
#endif
#ifdef CONFIG_X86_CYCLONE_TIMER
FIX_CYCLONE_TIMER, /*cyclone timer register*/
#endif
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
#ifdef CONFIG_PCI_MMCONFIG
FIX_PCIE_MCFG,
#endif
#ifdef CONFIG_PARAVIRT
FIX_PARAVIRT_BOOTMAP,
#endif
__end_of_permanent_fixed_addresses,
/*
* 256 temporary boot-time mappings, used by early_ioremap(),
* before ioremap() is functional.
*
* We round it up to the next 256 pages boundary so that we
* can have a single pgd entry and a single pte table:
*/
#define NR_FIX_BTMAPS 64
#define FIX_BTMAPS_SLOTS 4
FIX_BTMAP_END = __end_of_permanent_fixed_addresses + 256 -
(__end_of_permanent_fixed_addresses & 255),
FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS*FIX_BTMAPS_SLOTS - 1,
FIX_WP_TEST,
#ifdef CONFIG_ACPI
FIX_ACPI_BEGIN,
FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
#endif
#ifdef CONFIG_PROVIDE_OHCI1394_DMA_INIT
FIX_OHCI1394_BASE,
#endif
__end_of_fixed_addresses
};
其中每一个枚举量代表一个或一些页面,
除了NR_CPUS我们取1之外,其他的全都取最大值也不超过1K个页面
也就是说固定映射最多不到4M
再下面就是永久映射区域,先看看永久内核映射的起始地址定义
#define PKMAP_BASE ((FIXADDR_BOOT_START - PAGE_SIZE * (LAST_PKMAP + 1)) & PMD_MASK)
也就是说永久内核映射的起始地址是在固定内核映射-4M之下4M对齐的位置,
前面已经看到固定内核映射是小于4M的,因此永久内核映射的起始地址就在1G-8M的位置
在这里占用一个PMD,对于x86来说也就是占用4M的空间
再往下就是VMALLOC区了,看定义
# define VMALLOC_END (PKMAP_BASE - 2 * PAGE_SIZE)
就是说永久内核映射起始地址再往下2个页面就是VMALLOC_END了
因此VMALLOC_END = 1G-8M-2*4K
由此可得总的vmalloc空间为
VMALLOC_END - VMALLOC_START
= 1G-8M-2*4K - 904M
= 1048576k - 8192k - 8k - 925696k
= 114680k
现在看看
cat /proc/meminfo |grep VmallocTotal
是不是114680k?