Write in front
At the moment of linux startup, memory management has already started. In the kernel, allocator s that implement physical memory management include:
-
Initialization phase physical memory management memblock
-
Continuous physical memory management buddy allocator
-
Discontinuous physical memory management vmalloc allocator
-
Small physical memory management slab allocator
In the system initialization phase, a bootmem allocator and a memblock allocator will be enabled first. The bootmem allocator manages all the memory of a node node, including multiple bootmems in multiple nodes in numa architecture, which are linked to bdata_list is saved in the linked list. The initialization of the partner system is to release all the physical page boxes managed by bootmem to the partner system.
Next, let's briefly sort out the initialization process of the memory allocator (red part);
I. initialize buddy system
Each physical page (page frame) in the system memory corresponds to a struct page instance. Each memory domain is associated with an instance of struct zone. It holds the main array used to manage partner data.
mmzone.h
struct zone{
...
//Free area of no length
struct free_area free_area[MAX_ORDER];
...
};
free_area is an auxiliary data structure. It is defined as follows:
<mmzone.h>
struct free_area{
struct list_head_head free_list[MIGRATE_TYPES];
unsigned long nr_free;
};
nr_free specifies the number of empty free page blocks in the current memory area.
free_list is a linked list used to link free pages.
Order is a very important term in partner system. Describes the quantity unit of memory allocation. The length of the memory block is the order power of 2. The range of order is from 0 to MAX_ORDER.
26 /* Free memory management - zoned buddy allocator. */ 27 #ifndef CONFIG_FORCE_MAX_ZONEORDER 28 #define MAX_ORDER 11 29 #else 30 #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER 31 #endif 32 #define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1))
MAX_ The order setting is 11.
1.1 mem_init()
linux_mainline-5.17.0/arch/arm64/mm/init.c 374 void __init mem_init(void) 375 { 376 if (swiotlb_force == SWIOTLB_FORCE || 377 max_pfn > PFN_DOWN(arm64_dma_phys_limit)) 378 swiotlb_init(1); 379 else if (!xen_swiotlb_detect()) 380 swiotlb_force = SWIOTLB_NO_FORCE; 381 382 /* this will put all unused low memory onto the freelists */ //Partner system is a method to manage memory using page as a unit. Before the partner system takes over, deal with and establish mem_ For the section structure, the memory that is no longer used must be released from the Mem Block and handed over to the partner system for management 383 memblock_free_all(); 384 385 /* 386 * Check boundaries twice: Some fundamental inconsistencies can be 387 * detected at build time already. 388 */ 389 #ifdef CONFIG_COMPAT 390 BUILD_BUG_ON(TASK_SIZE_32 > DEFAULT_MAP_WINDOW_64); 391 #endif 392 393 /* 394 * Selected page table levels should match when derived from 395 * scratch using the virtual address range and page size. 396 */ 397 BUILD_BUG_ON(ARM64_HW_PGTABLE_LEVELS(CONFIG_ARM64_VA_BITS) != 398 CONFIG_PGTABLE_LEVELS); 399 400 if (PAGE_SIZE >= 16384 && get_num_physpages() <= 128) { 401 extern int sysctl_overcommit_memory; 402 /* 403 * On a machine this small we won't get anywhere without 404 * overcommit, so turn it on by default. 405 */ 406 sysctl_overcommit_memory = OVERCOMMIT_ALWAYS; 407 } 408 }
1.2 memblock_free_all()
Free pages to buddy allocator
linux_mainline-5.17.0/mm/memblock.c 2101 /** 2102 * memblock_free_all - release free pages to the buddy allocator 2103 */ 2104 void __init memblock_free_all(void) 2105 { 2106 unsigned long pages; 2107 2108 free_unused_memmap();//Release unused mem_map memory 2109 reset_all_zones_managed_pages();//Manage all nodes and all regions_ Pages is automatically set to 0 (managed_pages indicates the number of pages managed by the partner system). 2110 2111 pages = free_low_memory_core_early();//Mark the page corresponding to the memblock of the reserved type and the memory explicitly marked as Memory None as reserved(PG_reserved) Free the area of memory block type as memory and mark it as a free page 2112 totalram_pages_add(pages);//Increase_ totalram_pages, used to mark the total number of pages available in the system 2113 }
1.3 buddy allocation page
alloc_page(mask, order), allocate an order power of 2 and return an instance of struct page.
get_zeroed_page(mask), allocate a page and return a page instance.
__ get_free_page(mask,order) and__ get_free_page(mask), which returns the virtual address of the allocated memory block.
get_dma_pages(gfp_mask,order) to return the obtained DMA page.
1.4 buddy release page
free_page(struct page *) and free_pages(struct page *, order) is used to return one or two pages to the order power to the memory management subsystem.
__ free_page(struct page *) and__ free_ The meaning of pages (struct, Page *, order) is the same as above, but when it refers to the memory area to be released, the virtual address is used instead of the page instance.
2, Initialize Slab allocator
kmem_cache_init() mainly completes the initialization of the kernel slub memory allocation system.
huang: linux_mainline-5.17.0/mm/slab.c //slab (slub) initialization 1199 /* 1200 * Initialisation. Called after the page allocator have been initialised and 1201 * before smp_init(). 1202 */ 1203 void __init kmem_cache_init(void) 1204 { 1205 int i; 1206 //kmem_cache_init creates the first slab cache in the system for kmem_ The instance of cache provides memory. For this purpose, the kernel mainly uses static data created at compile time. In fact, a static data structure (initarray_cache) is used as a per CPU array. The name of the cache is kmem_cache_boot. 1207 kmem_cache = &kmem_cache_boot; 1208 1209 if (!IS_ENABLED(CONFIG_NUMA) || num_possible_nodes() == 1) 1210 use_alien_caches = 0; 1211 1212 for (i = 0; i < NUM_INIT_LISTS; i++) 1213 kmem_cache_node_init(&init_kmem_cache_node[i]); 1214 1215 /* 1216 * Fragmentation resistance on low memory - only use bigger 1217 * page orders on machines with more than 32MB of memory if 1218 * not overridden on the command line. 1219 */ 1220 if (!slab_max_order_set && totalram_pages() > (32 << 20) >> PAGE_SHIFT) 1221 slab_max_order = SLAB_MAX_ORDER_HI; 1222 1223 /* Bootstrap is tricky, because several objects are allocated 1224 * from caches that do not exist yet: 1225 * 1) initialize the kmem_cache cache: it contains the struct 1226 * kmem_cache structures of all caches, except kmem_cache itself: 1227 * kmem_cache is statically allocated. 1228 * Initially an __init data area is used for the head array and the 1229 * kmem_cache_node structures, it's replaced with a kmalloc allocated 1230 * array at the end of the bootstrap. 1231 * 2) Create the first kmalloc cache. 1232 * The struct kmem_cache for the new cache is allocated normally. 1233 * An __init data area is used for the head array. 1234 * 3) Create the remaining kmalloc caches, with minimally sized 1235 * head arrays. 1236 * 4) Replace the __init data head arrays for kmem_cache and the first 1237 * kmalloc cache with kmalloc allocated arrays. 1238 * 5) Replace the __init data for kmem_cache_node for kmem_cache and 1239 * the other cache's with kmalloc allocated memory. 1240 * 6) Resize the head arrays of the kmalloc caches to their final sizes. 1241 */ 1242 1243 /* 1) create the kmem_cache */ 1244 1245 /* 1246 * struct kmem_cache size depends on nr_node_ids & nr_cpu_ids 1247 */ //Call create_boot_cache creates a file named kmem_cache cache And add to slab_caches are in the chain 1248 create_boot_cache(kmem_cache, "kmem_cache", 1249 offsetof(struct kmem_cache, node) + 1250 nr_node_ids * sizeof(struct kmem_cache_node *), 1251 SLAB_HWCACHE_ALIGN, 0, 0); 1252 list_add(&kmem_cache->list, &slab_caches); 1253 slab_state = PARTIAL; 1254 1255 /* 1256 * Initialize the caches that provide memory for the kmem_cache_node 1257 * structures first. Without this, further allocations will bug. 1258 */ 1259 kmalloc_caches[KMALLOC_NORMAL][INDEX_NODE] = create_kmalloc_cache( 1260 kmalloc_info[INDEX_NODE].name[KMALLOC_NORMAL], 1261 kmalloc_info[INDEX_NODE].size, 1262 ARCH_KMALLOC_FLAGS, 0, 1263 kmalloc_info[INDEX_NODE].size); 1264 slab_state = PARTIAL_NODE; 1265 setup_kmalloc_cache_index_table(); 1266 1267 slab_early_init = 0; 1268 1269 /* 5) Replace the bootstrap kmem_cache_node */ 1270 { 1271 int nid; 1272 1273 for_each_online_node(nid) { 1274 init_list(kmem_cache, &init_kmem_cache_node[CACHE_CACHE + nid], nid); 1275 1276 init_list(kmalloc_caches[KMALLOC_NORMAL][INDEX_NODE], 1277 &init_kmem_cache_node[SIZE_NODE + nid], nid); 1278 } 1279 } 1280 1281 create_kmalloc_caches(ARCH_KMALLOC_FLAGS); 1282 }