![linux內存管理分析2_第1頁](http://file4.renrendoc.com/view/763a97c81b400c021a2d24c50d6a5105/763a97c81b400c021a2d24c50d6a51051.gif)
![linux內存管理分析2_第2頁](http://file4.renrendoc.com/view/763a97c81b400c021a2d24c50d6a5105/763a97c81b400c021a2d24c50d6a51052.gif)
![linux內存管理分析2_第3頁](http://file4.renrendoc.com/view/763a97c81b400c021a2d24c50d6a5105/763a97c81b400c021a2d24c50d6a51053.gif)
![linux內存管理分析2_第4頁](http://file4.renrendoc.com/view/763a97c81b400c021a2d24c50d6a5105/763a97c81b400c021a2d24c50d6a51054.gif)
![linux內存管理分析2_第5頁](http://file4.renrendoc.com/view/763a97c81b400c021a2d24c50d6a5105/763a97c81b400c021a2d24c50d6a51055.gif)
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、linux 內存管理分析【二】2012-11-19 21:09:22| 分類: 默認分類 | 標簽: | 字號大中小 訂閱2 內存管理系統(tǒng)建立過程為建立內存管理系統(tǒng),在內核初始化過程中調用了下面幾個函數:init/main.casmlinkage void _init start_kernel(void)初始化持久映射與臨時映射的一些信息,后面持久映射和臨時映射一節(jié)將詳細講解page_address_init();setup_arch 是特定于體系架構的函數,負責初始化自舉分配器和內核頁表等。setup_arch(&command_line);初始化 per_cpu 機制的一些結構,將.dat
2、a.percpu 段中的數據拷貝到每個CPU 的數據段中setup_per_cpu_areas();建立結點和內存域之間的關系build_all_zonelists(NULL);停用自舉分配器bootmem ,遷移到實際的內存管理中,初始化 slab 分配器,初始化進程虛擬地址空間管理結構mm_init();為每一個內存區(qū)域分配per_cpu_pageset 結構并初始化其成員setup_per_cpu_pageset();【 start_kernelsetup_arch 】arch/arm/kernel/setup.cvoid _init setup_arch(char *cmdline_p
3、)struct machine_desc *mdesc;內核參數可以通過平坦設備樹或者 tags 由 bootloader 傳遞給內核。每一個機器平臺都由一個struct machine_desc 結構來描述,內核所支持的所有平臺對應的machine_desc 結構都包含在段. 的 _arch_info_begin 到 _tagtable_end 之間。但每一個平臺都有其唯一的機器碼machine_arch_type , 可通過機器碼在段. 中找到對應的平臺描述結構。 函數 setup_machine_tags 就是根據機器碼找到對應的平臺描述結構,并且分析內核參數中內存相關的信息,用以初始化
4、內存塊管理結構membank 。mdesc = setup_machine_fdt(_atags_pointer);if (!mdesc)mdesc = setup_machine_tags(machine_arch_type);machine_desc = mdesc;machine_name = mdesc-name;根據 mdesc-dma_zone_size 設置 DMA 區(qū)域的大小 arm_dma_zone_size , 和 DMA 區(qū)域的結束地址 arm_dma_limitsetup_dma_zone(mdesc);結構 struct mm_struct 管理進程的虛擬地址空間,所
5、有內核線程都使用共同的地址空間,因為他們都是用相同的地址映射,這個地址空間由init_mm來描述。_text和_etext表示內核鏡像代碼段的起始和結束位置,_etext和_edata之間是已初始化數據段, _edata至Lend是未初始化數據段等, _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、內核命令行參數在函數setup_machine_tags 獲取并保存在了 boot_command_line 中strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);*cmdline_p = cmd_line;分析命令行參數,主要關注一些與內存相關的東西parse_early_param();將內存塊按從小到大排序sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank0), meminfo_cmp, NULL);掃描各個內存塊,檢測低端內存的最大值arm_lowmem_limi
7、t ,設置高端內存起始值的虛擬地址 high_memorysanity_check_meminfo();將所有內存塊添加到結構memblock 的 memory 區(qū)中, 將已使用的內存添加到 reserved 區(qū)中去。arm_memblock_init(&meminfo, mdesc);創(chuàng)建內核頁表,初始化自舉分配器paging_init(mdesc);內核中將許多物理資源用 struct resource 結構來管理, 下面函數就是將IO 內存作為 resource注冊到內核request_standard_resources(mdesc);如果內核命令行中有預留用于內核crash 是的轉存
8、空間,就將這些存儲空間標記為已分配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)根據機器號在段. 中尋找對應的 machine_desc 結構for_each_machine_desc(p)if (nr = p-nr) printk(Machine: %sn, p-name);mdesc = p;break; Bootloader 傳入的參數地址存放在_atags_pointer 中if (_atags_pointer)tags = phys_to_virt(_atags_pointer);else if (mdesc-atag_offset)tags = (void *)(PAGE_OFFSET + mdesc
10、-atag_offset);內核參數是由 struct tag 來管理,其中第一個tag 類型必然是ATAG_COREif (tags-hdr.tag != ATAG_CORE) tags = (struct tag *)&init_tags; 內核提供的一個默認參數列表函數 mdesc-fixup 中一般會獲取內存塊的信息if (mdesc-fixup)mdesc-fixup(tags, &from, &meminfo);if (tags-hdr.tag = ATAG_CORE) 如果內存塊已經初始化,就將參數列表中關于內存的參數標記為 ATAG_NONEif (meminfo.nr_ban
11、ks != 0)squash_mem_tags(tags);將參數列表拷貝到一個靜態(tài)數組 atags_copy 中save_atags(tags);分析內核參數,后面細講parse_tags(tags);將解析出來的內核命令行信息拷貝到靜態(tài)數組 boot_command_line 中。 在內核啟動期間用了很多靜態(tài)存儲空間,它們前面綴有_initdata ,像這樣的空間在內核啟動起來后將被釋放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)遍歷參數列表中每一個參數結構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;參數類型多種多樣解析方式也各不相同,所有針對每一種參數類型都有一個對應的解析函數,這些解析函數和其參數類型由結構struct tagtable 來管理。這些結構都存放在段.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參數中獲取內存信息,初始化內存塊管理結構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;遍歷每一個內存塊for (i = 0, j = 0; i start ULONG_MAX) highmem = 1;#ifdef CONFIG_HIGHMEMvmalloc_min 在 文 件 arch/arm/mm/mmu.c 中 定 義 , 它 定 義 了 高 端 內 存 的 起 始 位 置 。PAGE_OFFSE建物理位置的起始處。如果內存塊起始位置大于vmalloc_min ,表示存在高
17、端內存。如果內存擴展超過 32位,它就有可能小于 PAGE_OFFSETif (_va(bank-start) = vmalloc_min |_va(bank-start) highmem = highmem;如果該內存塊部分處于高端內存中,部分處于低端內存中就將其分為兩個內存塊。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 如果不支持高端內存做如下處理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求出低端內存的最大地址值if (!bank-highmem & bank-start + bank-size arm_lowmem_limit) arm_lowmem_limit = bank-start + bank-size;j+; meminfo.nr_banks = j; 記錄內存塊數計算高端內存起
20、始地址,該值不一定等于vmalloc_min ,因為可能沒有高端內存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;將所有內存模塊添加到 memblock.memory 中。結構體
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);如果內核在rom 中運行就只將它的數據段開始的空間添加到 memblock.reserved
22、中, 否則將內核代碼段開始的空間添加到 memblock.reserved 中。#ifdef CONFIG_XIP_KERNELmemblock_reserve(_pa(_sdata), _end - _sdata);#elsememblock_reserve(_pa(_stext), _end - _stext);#endif#ifdef CONFIG_BLK_DEV_INITRD如果支持 initrd 啟動,此時它還不在內存中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 鏡像預留一塊存儲區(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、內核頁表分配存儲空間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);根據不同的 arm 版本初始化不同的 mem_types ,該結構存放著頁表的一些屬性相關信息build_mem_type_table();將除了內核鏡像、主內存所在虛擬地址之外全部內存的頁表清除
26、掉prepare_page_table();為低端內存的所有區(qū)域創(chuàng)建內核頁表map_lowmem();對 DMA 區(qū)域重新創(chuàng)建頁表dma_contiguous_remap();為設備IO空間和中斷向量表創(chuàng)建頁表,并刷新 TLB和緩存 devicemaps_init(mdesc);獲取持久映射區(qū)頁表的位置,存儲在pkmap_page_table 中kmap_init();高 64K 是用于存放中斷向量表的top_pmd = pmd_off_k(0 xffff0000);分配一個 0 頁,該頁用于寫時復制機制。zero_page = early_alloc(PAGE_SIZE);初始化自舉內存分配
27、,后面有專門章節(jié)講解bootmem_init();empty_zero_page = virt_to_page(zero_page);刷新數據緩存_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;模塊力口載的范圍應該是在MODULES_VADDRgU MODUL
28、ES_EN0間,MODULES_VADDRfc文件 arch/arm/include/asm/memory.h 中定義,如下:#define MODULES_VADDR (PAGE_OFFSET - 8*1024*1024)對于arm處理器,該區(qū)域在正常內核虛擬地址之下。清除存儲空間在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 )是一種內核的同步機制。每CPU變量分為靜態(tài)變量和動態(tài)變量。靜態(tài)變量用 DEFINE_PER_CPU(type, nam既定義(CPU變量name,類型為type)。這 些靜態(tài)變量包含在段.data.percpu中。下面函數就是為每個CPU分配一部分空間用于動態(tài)分配pe
30、r_cpu變量。并為每個 CPU拷貝一份.data.percup段中的內容。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)設置 current_zonelist_order ,它決定備用內存域在 pglist_data-node_zonelists 中的排列順序 set_zonelist_order();if (system_state = SYSTEM_BOOTING) 初始化備用結點內存域列表pglist_data-node_zonelists 。_build_all_zonelists(NULL);mminit_verify_zonelist(); 打印一些調試信息當前進程的進程描述結構task_struct 中有一個成員
32、 mems_allowed ,該成員是nodemask_t類型的結構體,這個結構體在文件include/linux/nodemask.h 中定義如下:typedef struct DECLARE_BITMAP(bits, MAX_NUMNODES); nodemask_t;這個結構其實就是定義了一個位域, 每個位對應一個內存結點, 如果置 1 表示該節(jié)點內存可用。在下面函數中將這個位域中每個位置1 。cpuset_init_current_mems_allowed(); else #ifdef CONFIG_MEMORY_HOTPLUGif (data)setup_zone_pageset(s
33、truct zone *)data);#endif如果內核不是出于啟動過程中,就停止CPU的運行來初始化備用結點內存域列表stop_machine(_build_all_zonelists, NULL, NULL);計算總的空閑內存數vm_total_pages = nr_free_pagecache_pages();內核通過標記頁的可移動類型來避免產生過多碎片,如果可用內存太少就標記 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;遍歷每一個內存結點,初始化他們的備用結點內存域列表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 是備用結點內存域列表管理結構,該結構在文件include/linux/mmzone.h 中定義,如下:struct zonelist 指針 zlcache_ptr 通常指向本結構中的 zlcache 成員struct zonelist_cache *zlcache_ptr;MAX_ZONES_PER_ZONELIST示所有節(jié)點內存域總和struct zoneref _zonerefsMAX_ZONES_
36、PER_ZONELIST + 1;#ifdef CONFIG_NUMAstruct zonelist_cache zlcache;#endif;struct zoneref struct zone *zone; 指向內存域管理結構int zone_idx; 內存域所在結點 id;struct zonelist_cache 存儲所有內存域對應結點號unsigned short z_to_nMAX_ZONES_PER_ZONELIST;fullzones 是所有內存域的一個位圖,如果內存域對應位置1 ,表示這個內存域已沒有可用內存DECLARE_BITMAP(fullzones, MAX_ZONE
37、S_PER_ZONELIST);unsigned long last_full_zap;備用結點內存域列表中內存域排列原則是: 按分配代價由小到大排列。 在節(jié)點間應當先排列本地結點的內存域后排其他結點內存域, 在節(jié)點內先排列高端內存、 然后是普通內存、 再然后是 DMA 內存。在結點描述結構中,節(jié)點的備用結點內存域列表定義如下:typedef struct pglist_data struct zonelist node_zonelistsMAX_ZONELISTS;在多處理器系統(tǒng)中MAX_ZONELISTS定義為 2, node_zonelists0中排列本結點內存域,node_zoneli
38、sts1 中排列其他備用結點內存域。如果在找node_zonelists0 中不到可用內存就到 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;初始化備用結點內存域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;找一個與結點 pgdat 距離最近的結點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)將找到的最佳結點內存域排列到 pgdat 的備用內存域列表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); 將結點自己的內存域排列到自己的備用結點內存域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;函數 build_thisnode_zonelists 和本函數最大的區(qū)別就在于這里取的是node_zonelists0 ,而在函數 build_thisnode_zonelists 中取的是 node_zonelists1 。zonelist = &
43、pgdat-node_zonelists0;找到第一個空的位置for (j = 0; zonelist-_zonerefsj.zone != NULL; j+) ;將結點 node 的所有內存區(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 ,上層函數傳入的是MAX_NR_ZONES
45、 ,循環(huán)中做的就是將內存域按ZONE_HIGHMEMZONE_NORMAL-ZONE_DMA勺順序排歹 U 在備用內存歹 U 表中 zone_type-;zone = pgdat-node_zones + zone_type;if (populated_zone(zone) 函數zoneref_set_zone要做的就是用 zone和zone所在結點id來初始化_zonerefs。 zoneref_set_zone(zone,&zonelist-_zonerefsnr_zones+);找出整個備用列表中內存區(qū)域類型值最大的的內存區(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;讓結構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. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 產業(yè)基地自動扶梯裝修合同
- 文旅融合發(fā)展項目居間協(xié)議
- 丹陽六年級下數學試卷
- 橋梁液壓爬模專項施工方案
- 鐵路接觸網拆除施工方案
- 北海中學期末數學試卷
- 初三上學期中考數學試卷
- 西藏標志標牌施工方案
- 北師大數學六下數學試卷
- 書設計排版合同范本
- TSG ZF001-2006《安全閥安全技術監(jiān)察規(guī)程》
- 長螺旋鉆孔壓灌樁工程勞務清包合同(范本)
- 中考語文二輪復習:記敘文閱讀物象的作用(含練習題及答案)
- 老年外科患者圍手術期營養(yǎng)支持中國專家共識(2024版)
- 子宮畸形的超聲診斷
- 2024年1月高考適應性測試“九省聯考”數學 試題(學生版+解析版)
- JT-T-1004.1-2015城市軌道交通行車調度員技能和素質要求第1部分:地鐵輕軌和單軌
- (高清版)WST 408-2024 定量檢驗程序分析性能驗證指南
- 復工復產安全檢查記錄(總表)
- (正式版)JBT 11270-2024 立體倉庫組合式鋼結構貨架技術規(guī)范
- DB11∕T 2035-2022 供暖民用建筑室溫無線采集系統(tǒng)技術要求
評論
0/150
提交評論