版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、linux 內(nèi)存管理分析【二】2012-11-19 21:09:22| 分類: 默認(rèn)分類 | 標(biāo)簽: | 字號大中小 訂閱2 內(nèi)存管理系統(tǒng)建立過程為建立內(nèi)存管理系統(tǒng),在內(nèi)核初始化過程中調(diào)用了下面幾個函數(shù):init/main.casmlinkage void _init start_kernel(void)初始化持久映射與臨時映射的一些信息,后面持久映射和臨時映射一節(jié)將詳細(xì)講解page_address_init();setup_arch 是特定于體系架構(gòu)的函數(shù),負(fù)責(zé)初始化自舉分配器和內(nèi)核頁表等。setup_arch(&command_line);初始化 per_cpu 機制的一些結(jié)構(gòu),將.dat
2、a.percpu 段中的數(shù)據(jù)拷貝到每個CPU 的數(shù)據(jù)段中setup_per_cpu_areas();建立結(jié)點和內(nèi)存域之間的關(guān)系build_all_zonelists(NULL);停用自舉分配器bootmem ,遷移到實際的內(nèi)存管理中,初始化 slab 分配器,初始化進(jìn)程虛擬地址空間管理結(jié)構(gòu)mm_init();為每一個內(nèi)存區(qū)域分配per_cpu_pageset 結(jié)構(gòu)并初始化其成員setup_per_cpu_pageset();【 start_kernelsetup_arch 】arch/arm/kernel/setup.cvoid _init setup_arch(char *cmdline_p
3、)struct machine_desc *mdesc;內(nèi)核參數(shù)可以通過平坦設(shè)備樹或者 tags 由 bootloader 傳遞給內(nèi)核。每一個機器平臺都由一個struct machine_desc 結(jié)構(gòu)來描述,內(nèi)核所支持的所有平臺對應(yīng)的machine_desc 結(jié)構(gòu)都包含在段. 的 _arch_info_begin 到 _tagtable_end 之間。但每一個平臺都有其唯一的機器碼machine_arch_type , 可通過機器碼在段. 中找到對應(yīng)的平臺描述結(jié)構(gòu)。 函數(shù) setup_machine_tags 就是根據(jù)機器碼找到對應(yīng)的平臺描述結(jié)構(gòu),并且分析內(nèi)核參數(shù)中內(nèi)存相關(guān)的信息,用以初始化
4、內(nèi)存塊管理結(jié)構(gòu)membank 。mdesc = setup_machine_fdt(_atags_pointer);if (!mdesc)mdesc = setup_machine_tags(machine_arch_type);machine_desc = mdesc;machine_name = mdesc-name;根據(jù) mdesc-dma_zone_size 設(shè)置 DMA 區(qū)域的大小 arm_dma_zone_size , 和 DMA 區(qū)域的結(jié)束地址 arm_dma_limitsetup_dma_zone(mdesc);結(jié)構(gòu) struct mm_struct 管理進(jìn)程的虛擬地址空間,所
5、有內(nèi)核線程都使用共同的地址空間,因為他們都是用相同的地址映射,這個地址空間由init_mm來描述。_text和_etext表示內(nèi)核鏡像代碼段的起始和結(jié)束位置,_etext和_edata之間是已初始化數(shù)據(jù)段, _edata至Lend是未初始化數(shù)據(jù)段等, _end 之后便是堆區(qū)。init_mm.start_code = (unsigned long) _text;init_mm.end_code = (unsigned long) _etext;init_mm.end_data = (unsigned long) _edata;init_mm.brk = (unsigned long) _end;
6、內(nèi)核命令行參數(shù)在函數(shù)setup_machine_tags 獲取并保存在了 boot_command_line 中strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);*cmdline_p = cmd_line;分析命令行參數(shù),主要關(guān)注一些與內(nèi)存相關(guān)的東西parse_early_param();將內(nèi)存塊按從小到大排序sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank0), meminfo_cmp, NULL);掃描各個內(nèi)存塊,檢測低端內(nèi)存的最大值arm_lowmem_limi
7、t ,設(shè)置高端內(nèi)存起始值的虛擬地址 high_memorysanity_check_meminfo();將所有內(nèi)存塊添加到結(jié)構(gòu)memblock 的 memory 區(qū)中, 將已使用的內(nèi)存添加到 reserved 區(qū)中去。arm_memblock_init(&meminfo, mdesc);創(chuàng)建內(nèi)核頁表,初始化自舉分配器paging_init(mdesc);內(nèi)核中將許多物理資源用 struct resource 結(jié)構(gòu)來管理, 下面函數(shù)就是將IO 內(nèi)存作為 resource注冊到內(nèi)核request_standard_resources(mdesc);如果內(nèi)核命令行中有預(yù)留用于內(nèi)核crash 是的轉(zhuǎn)存
8、空間,就將這些存儲空間標(biāo)記為已分配reserve_crashkernel();【 start_kernelsetup_archsetup_machine_tags 】arch/arm/kernel/setup.cstatic struct machine_desc * _init setup_machine_tags(unsigned int nr)struct tag *tags = (struct tag *)&init_tags;struct machine_desc *mdesc = NULL, *p;char *from = default_command_line;init_tag
9、s.mem.start = PHYS_OFFSET;下面循環(huán)根據(jù)機器號在段. 中尋找對應(yīng)的 machine_desc 結(jié)構(gòu)for_each_machine_desc(p)if (nr = p-nr) printk(Machine: %sn, p-name);mdesc = p;break; Bootloader 傳入的參數(shù)地址存放在_atags_pointer 中if (_atags_pointer)tags = phys_to_virt(_atags_pointer);else if (mdesc-atag_offset)tags = (void *)(PAGE_OFFSET + mdesc
10、-atag_offset);內(nèi)核參數(shù)是由 struct tag 來管理,其中第一個tag 類型必然是ATAG_COREif (tags-hdr.tag != ATAG_CORE) tags = (struct tag *)&init_tags; 內(nèi)核提供的一個默認(rèn)參數(shù)列表函數(shù) mdesc-fixup 中一般會獲取內(nèi)存塊的信息if (mdesc-fixup)mdesc-fixup(tags, &from, &meminfo);if (tags-hdr.tag = ATAG_CORE) 如果內(nèi)存塊已經(jīng)初始化,就將參數(shù)列表中關(guān)于內(nèi)存的參數(shù)標(biāo)記為 ATAG_NONEif (meminfo.nr_ban
11、ks != 0)squash_mem_tags(tags);將參數(shù)列表拷貝到一個靜態(tài)數(shù)組 atags_copy 中save_atags(tags);分析內(nèi)核參數(shù),后面細(xì)講parse_tags(tags);將解析出來的內(nèi)核命令行信息拷貝到靜態(tài)數(shù)組 boot_command_line 中。 在內(nèi)核啟動期間用了很多靜態(tài)存儲空間,它們前面綴有_initdata ,像這樣的空間在內(nèi)核啟動起來后將被釋放strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);return mdesc;【 start_kernelsetup_archsetup_machine_
12、tagsparse_tags 】arch/arm/kernel/setup.cstatic void _init parse_tags(const struct tag *t)遍歷參數(shù)列表中每一個參數(shù)結(jié)構(gòu)for (; t-hdr.size; t = tag_next(t)if (!parse_tag(t) 【 start_kernelsetup_archsetup_machine_tagsparse_tagsparse_tag 】 arch/arm/kernel/setup.cstatic int _init parse_tag(const struct tag *tag)extern str
13、uct tagtable _tagtable_begin, _tagtable_end;struct tagtable *t;參數(shù)類型多種多樣解析方式也各不相同,所有針對每一種參數(shù)類型都有一個對應(yīng)的解析函數(shù),這些解析函數(shù)和其參數(shù)類型由結(jié)構(gòu)struct tagtable 來管理。這些結(jié)構(gòu)都存放在段.init.tagtable 的_tagtable_begin 和_tagtable_end 之間。for (t = &_tagtable_begin; t hdr.tag = t-tag) t-parse(tag);break;return t u.mem.start, tag-u.mem.size)
14、;_tagtable(ATAG_MEM, parse_tag_mem32);【 parse_tag_mem32arm_add_memory 】從ATAG_MEM參數(shù)中獲取內(nèi)存信息,初始化內(nèi)存塊管理結(jié)構(gòu)int _init arm_add_memory(phys_addr_t start, unsigned long size)struct membank *bank = &meminfo.bankmeminfo.nr_banks;if (meminfo.nr_banks = NR_BANKS) printk(KERN_CRIT NR_BANKS too low, ignoring memory
15、at 0 x%08llxn, (long long)start);return -EINVAL;size -= start & PAGE_MASK;bank-start = PAGE_ALIGN(start);#ifndef CONFIG_LPAEif (bank-start + size start) size = ULONG_MAX - bank-start;#endifbank-size = size & PAGE_MASK;if (bank-size = 0)return -EINVAL;meminfo.nr_banks+;return 0;【 start_kernelsetup_ar
16、chsanity_check_meminfo 】arch/arm/mm/mmu.cvoid _init sanity_check_meminfo(void) int i, j, highmem = 0;遍歷每一個內(nèi)存塊for (i = 0, j = 0; i start ULONG_MAX) highmem = 1;#ifdef CONFIG_HIGHMEMvmalloc_min 在 文 件 arch/arm/mm/mmu.c 中 定 義 , 它 定 義 了 高 端 內(nèi) 存 的 起 始 位 置 。PAGE_OFFSE建物理位置的起始處。如果內(nèi)存塊起始位置大于vmalloc_min ,表示存在高
17、端內(nèi)存。如果內(nèi)存擴展超過 32位,它就有可能小于 PAGE_OFFSETif (_va(bank-start) = vmalloc_min |_va(bank-start) highmem = highmem;如果該內(nèi)存塊部分處于高端內(nèi)存中,部分處于低端內(nèi)存中就將其分為兩個內(nèi)存塊。if (!highmem & _va(bank-start) size vmalloc_min - _va(bank-start) if (meminfo.nr_banks = NR_BANKS) else memmove(bank + 1, bank,(meminfo.nr_banks - i) * sizeof(
18、*bank);meminfo.nr_banks+;i+;bank1.size -= vmalloc_min - _va(bank-start);bank1.start = _pa(vmalloc_min - 1) + 1;bank1.highmem = highmem = 1;j+;bank-size = vmalloc_min - _va(bank-start);#else 如果不支持高端內(nèi)存做如下處理bank-highmem = highmem;if (highmem) continue;if (_va(bank-start) = vmalloc_min |va(bank-start) s
19、tart + bank-size) vmalloc_min |_va(bank-start + bank-size) start) unsigned long newsize = vmalloc_min - _va(bank-start);bank-size = newsize;#endif求出低端內(nèi)存的最大地址值if (!bank-highmem & bank-start + bank-size arm_lowmem_limit) arm_lowmem_limit = bank-start + bank-size;j+; meminfo.nr_banks = j; 記錄內(nèi)存塊數(shù)計算高端內(nèi)存起
20、始地址,該值不一定等于vmalloc_min ,因為可能沒有高端內(nèi)存high_memory = _va(arm_lowmem_limit - 1) + 1;memblock_set_current_limit(arm_lowmem_limit);【 start_kernelsetup_archarm_memblock_init 】arch/arm/mm/init.cvoid _init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) int i;將所有內(nèi)存模塊添加到 memblock.memory 中。結(jié)構(gòu)體
21、memblock 在文件 mm/memblock.c 中 定義,如下:struct memblock memblock _initdata_memblock = .memory.regions = memblock_memory_init_regions, .reserved.regions = memblock_reserved_init_regions, ;for (i = 0; i nr_banks; i+)memblock_add(mi-banki.start, mi-banki.size);如果內(nèi)核在rom 中運行就只將它的數(shù)據(jù)段開始的空間添加到 memblock.reserved
22、中, 否則將內(nèi)核代碼段開始的空間添加到 memblock.reserved 中。#ifdef CONFIG_XIP_KERNELmemblock_reserve(_pa(_sdata), _end - _sdata);#elsememblock_reserve(_pa(_stext), _end - _stext);#endif#ifdef CONFIG_BLK_DEV_INITRD如果支持 initrd 啟動,此時它還不在內(nèi)存中if (phys_initrd_size &!memblock_is_region_memory(phys_initrd_start, phys_initrd_siz
23、e) pr_err(INITRD: 0 x%08lx+0 x%08lx is not a memory region - disabling initrdn, phys_initrd_start, phys_initrd_size);phys_initrd_start = phys_initrd_size = 0;if (phys_initrd_size &memblock_is_region_reserved(phys_initrd_start, phys_initrd_size) pr_err(INITRD: 0 x%08lx+0 x%08lx overlaps in-use memory
24、 region - disabling initrdn, phys_initrd_start, phys_initrd_size);phys_initrd_start = phys_initrd_size = 0;為 inird 鏡像預(yù)留一塊存儲區(qū)if (phys_initrd_size) memblock_reserve(phys_initrd_start, phys_initrd_size);initrd_start = _phys_to_virt(phys_initrd_start);initrd_end = initrd_start + phys_initrd_size;#endif為
25、內(nèi)核頁表分配存儲空間arm_mm_memblock_reserve();【 start_kernelsetup_archpaging_init 】arch/arm/mm/mmu.cvoid _init paging_init(struct machine_desc *mdesc) void *zero_page;memblock_set_current_limit(arm_lowmem_limit);根據(jù)不同的 arm 版本初始化不同的 mem_types ,該結(jié)構(gòu)存放著頁表的一些屬性相關(guān)信息build_mem_type_table();將除了內(nèi)核鏡像、主內(nèi)存所在虛擬地址之外全部內(nèi)存的頁表清除
26、掉prepare_page_table();為低端內(nèi)存的所有區(qū)域創(chuàng)建內(nèi)核頁表map_lowmem();對 DMA 區(qū)域重新創(chuàng)建頁表dma_contiguous_remap();為設(shè)備IO空間和中斷向量表創(chuàng)建頁表,并刷新 TLB和緩存 devicemaps_init(mdesc);獲取持久映射區(qū)頁表的位置,存儲在pkmap_page_table 中kmap_init();高 64K 是用于存放中斷向量表的top_pmd = pmd_off_k(0 xffff0000);分配一個 0 頁,該頁用于寫時復(fù)制機制。zero_page = early_alloc(PAGE_SIZE);初始化自舉內(nèi)存分配
27、,后面有專門章節(jié)講解bootmem_init();empty_zero_page = virt_to_page(zero_page);刷新數(shù)據(jù)緩存_flush_dcache_page(NULL, empty_zero_page); 【 start_kernelsetup_archpaging_initprepare_page_table 】arch/arm/mm/mmu.cstatic inline void prepare_page_table(void) unsigned long addr;phys_addr_t end;模塊力口載的范圍應(yīng)該是在MODULES_VADDRgU MODUL
28、ES_EN0間,MODULES_VADDRfc文件 arch/arm/include/asm/memory.h 中定義,如下:#define MODULES_VADDR (PAGE_OFFSET - 8*1024*1024)對于arm處理器,該區(qū)域在正常內(nèi)核虛擬地址之下。清除存儲空間在MODULES_VADDR之下的頁表項。for (addr = 0; addr MODULES_VADDR; addr += PMD_SIZE) pmd_clear(pmd_off_k(addr);#ifdef CONFIG_XIP_KERNELaddr = (unsigned long)_etext + PMD
29、_SIZE - 1) & PMD_MASK;#endiffor ( ; addr = arm_lowmem_limit)end = arm_lowmem_limit;for (addr = _phys_to_virt(end);addr setup_per_cpu_areas 】每CPU變量(per- cpu-variable )是一種內(nèi)核的同步機制。每CPU變量分為靜態(tài)變量和動態(tài)變量。靜態(tài)變量用 DEFINE_PER_CPU(type, nam既定義(CPU變量name,類型為type)。這 些靜態(tài)變量包含在段.data.percpu中。下面函數(shù)就是為每個CPU分配一部分空間用于動態(tài)分配pe
30、r_cpu變量。并為每個 CPU拷貝一份.data.percup段中的內(nèi)容。mm/percpu.cvoid _init setup_per_cpu_areas(void) unsigned long delta;unsigned int cpu;int rc;rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE, PERCPU_DYNAMIC_RESERVE, PAGE_SIZE, NULL, pcpu_dfl_fc_alloc, pcpu_dfl_fc_free);if (rc build_all_zonelists 】mm/page_alloc
31、.cvoid _ref build_all_zonelists(void *data)設(shè)置 current_zonelist_order ,它決定備用內(nèi)存域在 pglist_data-node_zonelists 中的排列順序 set_zonelist_order();if (system_state = SYSTEM_BOOTING) 初始化備用結(jié)點內(nèi)存域列表pglist_data-node_zonelists 。_build_all_zonelists(NULL);mminit_verify_zonelist(); 打印一些調(diào)試信息當(dāng)前進(jìn)程的進(jìn)程描述結(jié)構(gòu)task_struct 中有一個成員
32、 mems_allowed ,該成員是nodemask_t類型的結(jié)構(gòu)體,這個結(jié)構(gòu)體在文件include/linux/nodemask.h 中定義如下:typedef struct DECLARE_BITMAP(bits, MAX_NUMNODES); nodemask_t;這個結(jié)構(gòu)其實就是定義了一個位域, 每個位對應(yīng)一個內(nèi)存結(jié)點, 如果置 1 表示該節(jié)點內(nèi)存可用。在下面函數(shù)中將這個位域中每個位置1 。cpuset_init_current_mems_allowed(); else #ifdef CONFIG_MEMORY_HOTPLUGif (data)setup_zone_pageset(s
33、truct zone *)data);#endif如果內(nèi)核不是出于啟動過程中,就停止CPU的運行來初始化備用結(jié)點內(nèi)存域列表stop_machine(_build_all_zonelists, NULL, NULL);計算總的空閑內(nèi)存數(shù)vm_total_pages = nr_free_pagecache_pages();內(nèi)核通過標(biāo)記頁的可移動類型來避免產(chǎn)生過多碎片,如果可用內(nèi)存太少就標(biāo)記 page_group_by_mobility_disabled 以禁用這種反碎片機制。if (vm_total_pages build_all_zonelists_build_all_zonelists 】 s
34、tatic _init_refok int _build_all_zonelists(void *data)int nid;int cpu;遍歷每一個內(nèi)存結(jié)點,初始化他們的備用結(jié)點內(nèi)存域列表for_each_online_node(nid) pg_data_t *pgdat = NODE_DATA(nid);build_zonelists(pgdat);build_zonelist_cache(pgdat);遍歷每一個CPU,初始化他們的per_cpu緩存for_each_possible_cpu(cpu) setup_pageset(&per_cpu(boot_pageset, cpu),
35、0);return 0;【 start_kernelbuild_all_zonelists_build_all_zonelistsbuild_zonelists】struct zonelist 是備用結(jié)點內(nèi)存域列表管理結(jié)構(gòu),該結(jié)構(gòu)在文件include/linux/mmzone.h 中定義,如下:struct zonelist 指針 zlcache_ptr 通常指向本結(jié)構(gòu)中的 zlcache 成員struct zonelist_cache *zlcache_ptr;MAX_ZONES_PER_ZONELIST示所有節(jié)點內(nèi)存域總和struct zoneref _zonerefsMAX_ZONES_
36、PER_ZONELIST + 1;#ifdef CONFIG_NUMAstruct zonelist_cache zlcache;#endif;struct zoneref struct zone *zone; 指向內(nèi)存域管理結(jié)構(gòu)int zone_idx; 內(nèi)存域所在結(jié)點 id;struct zonelist_cache 存儲所有內(nèi)存域?qū)?yīng)結(jié)點號unsigned short z_to_nMAX_ZONES_PER_ZONELIST;fullzones 是所有內(nèi)存域的一個位圖,如果內(nèi)存域?qū)?yīng)位置1 ,表示這個內(nèi)存域已沒有可用內(nèi)存DECLARE_BITMAP(fullzones, MAX_ZONE
37、S_PER_ZONELIST);unsigned long last_full_zap;備用結(jié)點內(nèi)存域列表中內(nèi)存域排列原則是: 按分配代價由小到大排列。 在節(jié)點間應(yīng)當(dāng)先排列本地結(jié)點的內(nèi)存域后排其他結(jié)點內(nèi)存域, 在節(jié)點內(nèi)先排列高端內(nèi)存、 然后是普通內(nèi)存、 再然后是 DMA 內(nèi)存。在結(jié)點描述結(jié)構(gòu)中,節(jié)點的備用結(jié)點內(nèi)存域列表定義如下:typedef struct pglist_data struct zonelist node_zonelistsMAX_ZONELISTS;在多處理器系統(tǒng)中MAX_ZONELISTS定義為 2, node_zonelists0中排列本結(jié)點內(nèi)存域,node_zoneli
38、sts1 中排列其他備用結(jié)點內(nèi)存域。如果在找node_zonelists0 中不到可用內(nèi)存就到 node_zonelists1 中去分配。mm/page_alloc.cstatic void build_zonelists(pg_data_t *pgdat)int j, node, load;enum zone_type i;nodemask_t used_mask;int local_node, prev_node;struct zonelist *zonelist;int order = current_zonelist_order;初始化備用結(jié)點內(nèi)存域for (i = 0; i node
39、_zonelists + i;zonelist-_zonerefs0.zone = NULL;zonelist-_zonerefs0.zone_idx = 0;local_node = pgdat-node_id;load = nr_online_nodes;prev_node = local_node;nodes_clear(used_mask);memset(node_order, 0, sizeof(node_order);j = 0;找一個與結(jié)點 pgdat 距離最近的結(jié)點while (node = find_next_best_node(local_node, &used_mask)
40、 = 0) int distance = node_distance(local_node, node);if (distance RECLAIM_DISTANCE)zone_reclaim_mode = 1;if (distance != node_distance(local_node, prev_node) node_loadnode = load;prev_node = node;load-;if (order = ZONELIST_ORDER_NODE)將找到的最佳結(jié)點內(nèi)存域排列到 pgdat 的備用內(nèi)存域列表node_zonelists1 中build_zonelists_in_n
41、ode_order(pgdat, node);elsenode_orderj+ = node; /* remember order */if (order = ZONELIST_ORDER_ZONE) /* calculate node order - i.e., DMA last! */ build_zonelists_in_zone_order(pgdat, j); 將結(jié)點自己的內(nèi)存域排列到自己的備用結(jié)點內(nèi)存域node_zonelists0 中build_thisnode_zonelists(pgdat);【 start_kernelbuild_all_zonelists_build_al
42、l_zonelistsbuild_zonelistsbuild_zonelists_in_node_order 】mm/page_alloc.cstatic void build_zonelists_in_node_order(pg_data_t *pgdat, int node) int j;struct zonelist *zonelist;函數(shù) build_thisnode_zonelists 和本函數(shù)最大的區(qū)別就在于這里取的是node_zonelists0 ,而在函數(shù) build_thisnode_zonelists 中取的是 node_zonelists1 。zonelist = &
43、pgdat-node_zonelists0;找到第一個空的位置for (j = 0; zonelist-_zonerefsj.zone != NULL; j+) ;將結(jié)點 node 的所有內(nèi)存區(qū)域排列在, j 開始的備用列表中j = build_zonelists_node(NODE_DATA(node), zonelist, j,MAX_NR_ZONES - 1);zonelist-_zonerefsj.zone = NULL;zonelist-_zonerefsj.zone_idx = 0;【 start_kernelbuild_all_zonelists_build_all_zoneli
44、stsbuild_zonelistsbuild_zonelists_in_node_orderbuild_zonelists_node 】mm/page_alloc.cstatic int build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist,int nr_zones, enum zone_type zone_type) struct zone *zone;BUG_ON(zone_type = MAX_NR_ZONES);zone_type+;do 這里的 zone_type ,上層函數(shù)傳入的是MAX_NR_ZONES
45、 ,循環(huán)中做的就是將內(nèi)存域按ZONE_HIGHMEMZONE_NORMAL-ZONE_DMA勺順序排歹 U 在備用內(nèi)存歹 U 表中 zone_type-;zone = pgdat-node_zones + zone_type;if (populated_zone(zone) 函數(shù)zoneref_set_zone要做的就是用 zone和zone所在結(jié)點id來初始化_zonerefs。 zoneref_set_zone(zone,&zonelist-_zonerefsnr_zones+);找出整個備用列表中內(nèi)存區(qū)域類型值最大的的內(nèi)存區(qū)域check_highest_zone(zone_type);
46、while (zone_type);return nr_zones;【 start_kernelbuild_all_zonelists_build_all_zonelistsbuild_zonelist_cache】mm/page_alloc.cstatic void build_zonelist_cache(pg_data_t *pgdat)struct zonelist *zonelist;struct zonelist_cache *zlc;struct zoneref *z;zonelist = &pgdat-node_zonelists0;讓結(jié)構(gòu)struct zonelist的zlcache_ptr指針成員指向它自己的zlcache成員zonelist-zlcache_ptr = zlc = &zonelist-zlcache;bitmap_zero(zlc-fullzones, MAX_ZONES_PER_ZONELIST);for (z = zonelist-_zonerefs; z-zone; z+)zlc-z_t
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年鐵路信號控制設(shè)備項目可行性研究報告
- 2025年度智能安防股權(quán)投資合作協(xié)議范本
- 2025年度借款授權(quán)委托書金融機構(gòu)定制模板
- 2025年中國載重卡車行業(yè)市場調(diào)研分析及投資戰(zhàn)略咨詢報告
- 2025年度公共安全合同管理及應(yīng)急響應(yīng)協(xié)議
- 2025年中國相機支架行業(yè)市場全景監(jiān)測及投資戰(zhàn)略咨詢報告
- 2025年度陵園土地承包經(jīng)營二零二五版合同
- 旅游列車與景區(qū)溝通平臺建設(shè)的必要性
- 2025年度醫(yī)療健康產(chǎn)業(yè)合作分紅合同范本
- 2025年度國有土地租賃合同范本(含配套設(shè)施)
- 培訓(xùn)課件:律師客戶溝通技巧
- 2024年石柱土家族自治縣中醫(yī)院高層次衛(wèi)技人才招聘筆試歷年參考題庫頻考點附帶答案
- 西藏事業(yè)單位c類歷年真題
- 2025中國移動安徽分公司春季社會招聘高頻重點提升(共500題)附帶答案詳解
- 七年級英語下學(xué)期開學(xué)考試(深圳專用)-2022-2023學(xué)年七年級英語下冊單元重難點易錯題精練(牛津深圳版)
- 2025江蘇省全日制勞動合同書范本
- 放射科護(hù)理常規(guī)
- 儒釋道文化秒解
- 新時代中小學(xué)教師職業(yè)行為十項準(zhǔn)則
- 人教版八年級上冊英語1-4單元測試卷(含答案)
- 初中數(shù)學(xué)教學(xué)經(jīng)驗分享
評論
0/150
提交評論