vmemmap是内核中page 数据的虚拟地址。针对sparse内存模型。内核申请page获取的page地址从此开始。

SPARSEMEM原理:

  • section的概念:

SPARSEMEM内存模型引入了section的概念,可以简单将它理解为struct page的集合(数组)。内核使用struct mem_section去描述section,定义如下:

struct mem_section {unsigned long section_mem_map;/* See declaration of similar field in struct zone */unsigned long *pageblock_flags;
};

其中的section_mem_map成员存放的是struct page数组的地址,每个section可容纳PFN_SECTION_SHIFT个struct page,arm64地址位宽为48bit时定义了每个section可囊括的地址范围是1GB。

  • 全局变量**mem_section

内核中用了一个二级指针struct mem_section **mem_section去管理section,我们可以简单理解为一个动态的二维数组。所谓二维即内核又将SECTIONS_PER_ROOT个section划分为一个ROOT,ROOT的个数不是固定的,根据系统实际的物理地址大小来分配。

  • 物理页帧号PFN

SPARSEMEM将PFN差分成了三个level,每个level分别对应:ROOT编号、ROOT内的section偏移、section内的page偏移。(可以类比多级页表来理解)

  • vmemmap区域

vmemmap区域是一块起始地址是VMEMMAP_START,范围是2TB的虚拟地址区域,位于kernel space。以section为单位来存放strcut page结构的虚拟地址空间,然后线性映射到物理内存。

  • PFN和struct page的转换:

SPARSEMEM中__pfn_to_page和__page_to_pfn的实现如下:

#define __pfn_to_page(pfn)      (vmemmap + (pfn))
#define __page_to_pfn(page)     (unsigned long)((page) - vmemmap)
#define vmemmap        ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))

其中vmemmap指针指向VMEMMAP_START偏移memstart_addr的地址处,memstart_addr则是根据物理起始地址PHYS_OFFSET算出来的偏移。

arm64:setup_arch(arch/arm64/kernel/setup.c)

->bootmem_init->sparse_init

void __init bootmem_init(void)
{unsigned long min, max;min = PFN_UP(memblock_start_of_DRAM());max = PFN_DOWN(memblock_end_of_DRAM());early_memtest(min << PAGE_SHIFT, max << PAGE_SHIFT);max_pfn = max_low_pfn = max;arm64_numa_init();/** Sparsemem tries to allocate bootmem in memory_present(), so must be* done after the fixed reservations.*/arm64_memory_present();sparse_init();zone_sizes_init(min, max);memblock_dump_all();
}void __init sparse_init(void)
{unsigned long pnum_begin = first_present_section_nr();int nid_begin = sparse_early_nid(__nr_to_section(pnum_begin));unsigned long pnum_end, map_count = 1;/* Setup pageblock_order for HUGETLB_PAGE_SIZE_VARIABLE */set_pageblock_order();printk("===sparse_init nid_begin %d pnum_begin %llu  pnum_end %llu \n",nid_begin,pnum_begin,pnum_end);for_each_present_section_nr(pnum_begin + 1, pnum_end) {int nid = sparse_early_nid(__nr_to_section(pnum_end));if (nid == nid_begin) {map_count++;continue;}/* Init node with sections in range [pnum_begin, pnum_end) */printk("===sparse_init::sparse_init_nid 0 nid_begin %d pnum_begin %llu pnum_end %llu map_count %d\n",nid_begin, pnum_begin, pnum_end, map_count);sparse_init_nid(nid_begin, pnum_begin, pnum_end, map_count);nid_begin = nid;pnum_begin = pnum_end;map_count = 1;}/* cover the last node */printk("===sparse_init::sparse_init_nid 1  nid_begin %d pnum_begin %llu pnum_end %llu map_count %d\n",nid_begin, pnum_begin, pnum_end, map_count);sparse_init_nid(nid_begin, pnum_begin, pnum_end, map_count);vmemmap_populate_print_last();
}

在S2500服务器上,16个NODE节点的情况下,日志如下,可以看出每个node的map_count为32 也就是每个NODE内存32G。因为每个map_section代表1G内存。
[    0.000000] ===sparse_init nid_begin 0 pnum_begin 2  pnum_end 0 
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 0 pnum_begin 2 pnum_end 1088 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 1 pnum_begin 1088 pnum_end 1152 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 2 pnum_begin 1152 pnum_end 1216 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 3 pnum_begin 1216 pnum_end 1280 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 4 pnum_begin 1280 pnum_end 1344 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 5 pnum_begin 1344 pnum_end 1408 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 6 pnum_begin 1408 pnum_end 1472 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 7 pnum_begin 1472 pnum_end 2050 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 8 pnum_begin 2050 pnum_end 3136 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 9 pnum_begin 3136 pnum_end 3200 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 10 pnum_begin 3200 pnum_end 3264 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 11 pnum_begin 3264 pnum_end 3328 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 12 pnum_begin 3328 pnum_end 3392 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 13 pnum_begin 3392 pnum_end 3456 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 0 nid_begin 14 pnum_begin 3456 pnum_end 3520 map_count 32
[    0.000000] ===sparse_init::sparse_init_nid 1  nid_begin 15 pnum_begin 3520 pnum_end 18446744073709551615 map_count 32

//最后的pnum_end是上面循环的原因导致到了最后一个section。不过其中大多数是不存在实际物理内存。通过for_each_present_section_nr 可以循环其中存在的section。确定section的内容参考函数arm64_memory_present。

sparse_init_nid解析一个node节点的物理内存:

static void __init sparse_init_nid(int nid, unsigned long pnum_begin,unsigned long pnum_end,unsigned long map_count)
{unsigned long pnum, usemap_longs, *usemap;struct page *map;usemap_longs = BITS_TO_LONGS(SECTION_BLOCKFLAGS_BITS);usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nid),usemap_size() *map_count);if (!usemap) {pr_err("%s: node[%d] usemap allocation failed", __func__, nid);goto failed;}printk("===sparse_init_nid nid %d pnum_begin  %llu  pnum_end %llu \n",nid,pnum_begin,pnum_end);sparse_buffer_init(map_count * section_map_size(), nid);for_each_present_section_nr(pnum_begin, pnum) {if (pnum >= pnum_end)break;printk("===sparse_init_nid loop nid %d pnum %llu \n",nid,pnum);map = sparse_mem_map_populate(pnum, nid, NULL);if (!map) {pr_err("%s: node[%d] memory map backing failed. Some memory will not be available.",__func__, nid);pnum_begin = pnum;goto failed;}check_usemap_section_nr(nid, usemap);sparse_init_one_section(__nr_to_section(pnum), pnum, map, usemap);usemap += usemap_longs;}sparse_buffer_fini();return;
failed:/* We failed to allocate, mark all the following pnums as not present */for_each_present_section_nr(pnum_begin, pnum) {struct mem_section *ms;if (pnum >= pnum_end)break;ms = __nr_to_section(pnum);ms->section_mem_map = 0;}
}

[    0.000000] ===sparse_init_nid nid 0 pnum_begin  2  pnum_end 1088 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 2 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 3 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1024 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1025 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1028 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1029 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1030 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1031 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1032 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1033 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1034 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1035 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1036 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1037 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1038 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1039 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1056 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1057 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1058 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1059 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1060 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1061 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1062 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1063 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1064 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1065 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1066 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1067 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1068 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1069 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1070 
[    0.000000] ===sparse_init_nid loop nid 0 pnum 1071 
[    0.000000] ===sparse_init_nid nid 1 pnum_begin  1088  pnum_end 1152 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1088 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1089 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1090 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1091 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1092 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1093 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1094 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1095 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1096 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1097 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1098 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1099 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1100 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1101 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1102 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1103 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1120 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1121 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1122 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1123 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1124 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1125 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1126 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1127 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1128 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1129 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1130 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1131 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1132 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1133 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1134 
[    0.000000] ===sparse_init_nid loop nid 1 pnum 1135 
[    0.000000] ===sparse_init_nid nid 2 pnum_begin  1152  pnum_end 1216

[    0.000000] ===sparse_init_nid loop nid 2 pnum 1152

。。。

省略

。。。

[    0.000000] ===sparse_init_nid nid 3 pnum_begin  1216  pnum_end 1280

。。。
[    0.000000] ===sparse_init_nid nid 4 pnum_begin  1280  pnum_end 1344

。。。
[    0.000000] ===sparse_init_nid nid 5 pnum_begin  1344  pnum_end 1408

。。。
[    0.000000] ===sparse_init_nid nid 6 pnum_begin  1408  pnum_end 1472

。。。
[    0.000000] ===sparse_init_nid nid 7 pnum_begin  1472  pnum_end 2050

。。。
[    0.000000] ===sparse_init_nid nid 8 pnum_begin  2050  pnum_end 3136

。。。
[    0.000000] ===sparse_init_nid nid 9 pnum_begin  3136  pnum_end 3200

。。。
[    0.000000] ===sparse_init_nid nid 10 pnum_begin  3200  pnum_end 3264

。。。
[    0.000000] ===sparse_init_nid nid 11 pnum_begin  3264  pnum_end 3328

。。。
[    0.000000] ===sparse_init_nid nid 12 pnum_begin  3328  pnum_end 3392

。。。
[    0.000000] ===sparse_init_nid nid 13 pnum_begin  3392  pnum_end 3456

。。。
[    0.000000] ===sparse_init_nid nid 14 pnum_begin  3456  pnum_end 3520

。。。
[    0.000000] ===sparse_init_nid nid 15 pnum_begin  3520  pnum_end

18446744073709551615
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3520 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3521 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3522 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3523 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3524 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3525 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3526 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3527 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3528 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3529 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3530 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3531 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3532 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3533 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3534 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3535 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3552 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3553 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3554 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3555 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3556 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3557 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3558 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3559 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3560 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3561 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3562 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3563 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3564 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3565 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3566 
[    0.000000] ===sparse_init_nid loop nid 15 pnum 3567

上述日志。在确定的一个nid中,循环一个存在的section。可以看到循环的次数是32。

前面已经得出每个node下的物理内存。且已经完成**mem_section 的创建。虽然此时page的地址已经确定,单具体的内容还是空的。mem_section对应一个G的物理内存,所有page的内容要根据实际物理内存来初始化。

bootmem_init

zone_sizes_init

free_area_init_nodes
                    free_area_init_node
                        calculate_node_totalpages
                        free_area_init_core
                            memmap_init(memmap_init_zone)
                                __init_single_page

在memmap_init_zone函数中,会根据实际的物理内存进行page的初始化,调用__init_single_page函数。下面我就打印

void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,unsigned long start_pfn, enum memmap_context context,struct vmem_altmap *altmap)
{unsigned long realcount = 0 ;unsigned long end_pfn = start_pfn + size;pg_data_t *pgdat = NODE_DATA(nid);unsigned long pfn;unsigned long nr_initialised = 0;struct page *page;
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAPstruct memblock_region *r = NULL, *tmp;
#endifif (highest_memmap_pfn < end_pfn - 1)highest_memmap_pfn = end_pfn - 1;/** Honor reservation requested by the driver for this ZONE_DEVICE* memory*/if (altmap && start_pfn == altmap->base_pfn)start_pfn += altmap->reserve;for (pfn = start_pfn; pfn < end_pfn; pfn++) {/** There can be holes in boot-time mem_map[]s handed to this* function.  They do not exist on hotplugged memory.*/if (context != MEMMAP_EARLY)goto not_early;if (!early_pfn_valid(pfn))continue;if (!early_pfn_in_nid(pfn, nid))continue;if (!update_defer_init(pgdat, pfn, end_pfn, &nr_initialised))break;
。。。。。省略。。。。。。not_early:realcount++;page = pfn_to_page(pfn);__init_single_page(page, pfn, zone, nid);if (context == MEMMAP_HOTPLUG)SetPageReserved(page);if (!(pfn & (pageblock_nr_pages - 1))) {set_pageblock_migratetype(page, MIGRATE_MOVABLE);cond_resched();}}printk("===memmap_init_zone nid %d size %llu zone %llu start_pfn %llu readlcount  %llu\n",nid,size,zone,start_pfn,realcount);
}

下面打印除了每个node下时间的page数量。并初始化page结构内容。

[    0.000000] ===memmap_init_zone nid 0 size 32768 zone 0 start_pfn 32768 readlcount  31661
[    0.000000] ===memmap_init_zone nid 0 size 17498112 zone 1 start_pfn 65536 readlcount  490496
[    0.000000] ===memmap_init_zone nid 1 size 786432 zone 1 start_pfn 17825792 readlcount  524288
[    0.000000] ===memmap_init_zone nid 2 size 786432 zone 1 start_pfn 18874368 readlcount  524288
[    0.000000] ===memmap_init_zone nid 3 size 786432 zone 1 start_pfn 19922944 readlcount  524288
[    0.000000] ===memmap_init_zone nid 4 size 786432 zone 1 start_pfn 20971520 readlcount  524288
[    0.000000] ===memmap_init_zone nid 5 size 786432 zone 1 start_pfn 22020096 readlcount  524288
[    0.000000] ===memmap_init_zone nid 6 size 786432 zone 1 start_pfn 23068672 readlcount  524288
[    0.000000] ===memmap_init_zone nid 7 size 786432 zone 1 start_pfn 24117248 readlcount  524288
[    0.000000] ===memmap_init_zone nid 8 size 17530880 zone 1 start_pfn 33587200 readlcount  523264
[    0.000000] ===memmap_init_zone nid 9 size 786432 zone 1 start_pfn 51380224 readlcount  524288
[    0.000000] ===memmap_init_zone nid 10 size 786432 zone 1 start_pfn 52428800 readlcount  524288
[    0.000000] ===memmap_init_zone nid 11 size 786432 zone 1 start_pfn 53477376 readlcount  524288
[    0.000000] ===memmap_init_zone nid 12 size 786432 zone 1 start_pfn 54525952 readlcount  524288
[    0.000000] ===memmap_init_zone nid 13 size 786432 zone 1 start_pfn 55574528 readlcount  524288
[    0.000000] ===memmap_init_zone nid 14 size 786432 zone 1 start_pfn 56623104 readlcount  524288
[    0.000000] ===memmap_init_zone nid 15 size 786432 zone 1 start_pfn 57671680 readlcount  524288

测试page地址是否在VMEMMAP定义的地址范围:

#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/mm.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/io.h>static int __init test_init(void)
{struct page *page;unsigned long vaddr ;printk("VMEMMAP_START %llx vmemmap %llx \n ",VMEMMAP_START,vmemmap);page = alloc_pages(GFP_ATOMIC & ~__GFP_HIGHMEM, 0);if (!page)return 0;printk("page_to_pfn(%llx):%llu  pa  %llx \n",page,page_to_pfn(page),PFN_PHYS(page_to_pfn(page)));vaddr = page_address(page);printk("page %llx vaddr %llx \n",page,vaddr);printk(KERN_INFO "test_init\n");return 0;
}static void __exit test_exit(void)
{printk(KERN_INFO "test_exit\n");
}module_init(test_init);
module_exit(test_exit);MODULE_LICENSE("GPL");

输出:

[239935.492355] VMEMMAP_START ffff7fe000000000 vmemmap ffff7fdfffe00000 
                 
[239935.492359] page_to_pfn(ffff7fe008b6f100):2317252  pa  235bc40000 
[239935.518223] page ffff7fe008b6f100 vaddr ffff8022dbc40000

page地址在VMEMMAP_START 开始。最终的虚拟地址是通过pfn->pa->va。 虚拟地址自然是内核之前映射的线性地址区间。

arm64内核内存布局-vmemmap笔记相关推荐

  1. ARM64内核内存布局图

    ARM64架构处理器采用48位物理寻址机制,最大可以寻找到256TB的物理地址空间.对于目前的应用来说已经足够了,不需要扩展到64位的物理地址寻址.虚拟地址也同样最大支持48位支持,所以在处理器的架构 ...

  2. 【Linux 内核 内存管理】Linux 内核内存布局 ④ ( ARM64 架构体系内存分布 | 内核启动源码 start_kernel | 内存初始化 mm_init | mem_init )

    文章目录 一.ARM64 架构体系内存分布 二.Linux 内核启动源码 start_kernel 三.内存初始化源码 mm_init 四.内存初始化源码 mem_init 一.ARM64 架构体系内 ...

  3. 【Linux 内核 内存管理】Linux 内核内存布局 ③ ( Linux 内核 动态分配内存 系统接口函数 | 统计输出 vmalloc 分配的内存 )

    文章目录 一.Linux 内核 动态分配内存 系统接口函数 二.统计输出 vmalloc 分配的内存 一.Linux 内核 动态分配内存 系统接口函数 Linux 内核 " 动态分配内存 & ...

  4. 【Linux 内核 内存管理】Linux 内核内存布局 ② ( x86_64 架构体系内存分布 | 查看 /proc/meminfo 文件 | /proc/meminfo 重要字段解析 )

    文章目录 一.查看 x86_64 架构体系内存分布 二./proc/meminfo 重要字段解析 一.查看 x86_64 架构体系内存分布 执行 cat /proc/meminfo 命令 , 可以查看 ...

  5. 【Linux 内核 内存管理】Linux 内核内存布局 ① ( 查看 Linux 操作系统位数 | 查看 Linux 操作系统软硬件信息 )

    文章目录 一.查看 Linux 操作系统位数 二.查看 Linux 操作系统软硬件信息 一.查看 Linux 操作系统位数 在 646464 位的 Linux 中 , 使用 484848 位 表示 & ...

  6. 详解 ARM64 内核中对 52 位虚拟地址的支持

    当 64 位硬件变得可用之后,处理更大地址空间(大于 232 字节)的需求变得显而易见.现如今一些公司已经提供 64TiB 或更大内存的服务器,x86_64 架构和 arm64 架构现在允许寻址的地址 ...

  7. 【Linux 内核 内存管理】内存映射原理 ① ( 物理地址空间 | 外围设备寄存器 | 外围设备寄存器的物理地址 映射到 虚拟地址空间 )

    文章目录 一.物理地址空间 二.外围设备寄存器 三.外围设备寄存器物理地址 映射到 虚拟地址空间 一.物理地址空间 " 物理地址空间 " 是 CPU 处理器 在 " 总线 ...

  8. 10.操作系统实战——二级引导器探查收集信息(检查CPU,获取内存布局,初始化内核栈,放置内核文件和字库文件,建立MMU页表,设置图形模式,显示LOGO)

    该课程来自极客时间<操作系统实战45讲>,踩坑笔记,具体操作步骤见"显示logo"目录. 在二级引导器中,我们要检查 CPU 是否支持 64 位的工作模式.收集内存布局 ...

  9. Linux进程地址空间与进程内存布局详解,内核空间与用户空间

    Linux进程地址空间与进程内存布局详解 程序段(Text):程序代码在内存中的映射,存放函数体的二进制代码. 初始化过的数据(Data):在程序运行初已经对变量进行初始化的数据. 未初始化过的数据( ...

最新文章

  1. 怎么删除github上的仓库?
  2. Ansible管理节点过多导致的超时问题解决方法
  3. android解析ip地址,android – 如何从IP地址解析网络主机名
  4. iview select 怎么清空_在使用iview时发现要先重置一下表单然后填写完后再重置可以清空Select多选框,否则清不掉,什么原因?...
  5. [转载] Python基础之类型转换与算术运算符
  6. 为什么说容器的崛起预示着云原生时代到来?
  7. kafka基础之介绍和分布式集群搭建
  8. Java中Integer与String类型互转
  9. Eclipse 快捷键 (应用中自己总结)
  10. 如何在word2016中使用自带的公式编辑器
  11. oracle asm掉盘,ASM Disk丢失的临时解决方法
  12. 深度剖析mongos连接池
  13. angular 获取上一个路由地址 获取当前页地址 地址裁切
  14. git branch -f的作用
  15. UpdateData()函数的用法
  16. C#毕业设计——基于C#+asp.net+SQL server的网上物流管理信息系统设计与实现(毕业论文+程序源码)——网上物流管理信息系统
  17. 随手科技累计用户超3亿 领跑互金App
  18. ABB机器人随机物料抓取优化升级
  19. 21华为杯数学建模B题--空气质量二次预测
  20. shellcode教程从新手到高手

热门文章

  1. 怎样在一台电脑里访问其他电脑里的虚拟机
  2. Java对字符串中数字进行按自然顺序排序
  3. 数据库的脏读,幻读,幻行的原理及解决方式
  4. execl(知道每个商品单价,且知道总价,计算每个商品的数量)
  5. 数字电路实验(01)基本逻辑运算及其电路实现
  6. C语言:求100以内的素数
  7. [教程] 我家云刷armbian+安装LMS
  8. numpy_amin函数
  9. Python 小练习 100 例 (边练习边更新)
  10. 数学建模方法——SPSS主成分分析法