Rumah >Tutorial sistem >LINUX >Teknologi pencegahan pemecahan memori kernel Linux: pemahaman mendalam tentang pengurusan memori

Teknologi pencegahan pemecahan memori kernel Linux: pemahaman mendalam tentang pengurusan memori

WBOY
WBOYke hadapan
2024-02-12 09:54:15884semak imbas

Pernahkah anda menghadapi pelbagai masalah ingatan dalam sistem Linux? Seperti kebocoran memori, pemecahan memori, dll. Masalah ini boleh diselesaikan dengan pemahaman mendalam tentang teknologi pencegahan pemecahan memori kernel Linux.

Linux kernel内存碎片防治技术:深入理解内存管理

Cara kernel Linux mengatur dan mengurus memori fizikal ialah sistem buddy, dan pemecahan memori fizikal adalah salah satu kelemahan sistem buddy Untuk mencegah dan menyelesaikan masalah pemecahan, kernel telah menggunakan beberapa teknologi praktikal akan diringkaskan di sini.

1 Satukan serpihan apabila daya ingatan rendah

Gunakan halaman memori daripada rakan Jika tiada halaman yang sesuai ditemui, dua langkah pelarasan memori akan dilakukan, padat dan tuntut semula. Yang pertama adalah untuk menyatukan serpihan untuk mendapatkan memori bersebelahan yang lebih besar; yang kedua adalah untuk mengitar semula memori penimbal yang tidak semestinya menduduki memori. Fokus di sini adalah untuk memahami comact Keseluruhan proses adalah secara kasar seperti berikut:

__alloc_pages_nodemask
  -> __alloc_pages_slowpath
    -> __alloc_pages_direct_compact
      -> try_to_compact_pages
        -> compact_zone_order
          -> compact_zone
            -> isolate_migratepages
            -> migrate_pages
            -> release_freepages
并不是所有申请不到内存的场景都会compact,首先要满足order大于0,并且gfp_mask携带__

GFP_FS dan __GFP_IO; Selain itu, baki memori zon perlu memenuhi syarat tertentu. Kernel memanggilnya sebagai "indeks pemecahan". daripada 500. Nilai lalai ini boleh dilaraskan melalui fail proc extfrag_threshold. Indeks fragmentasi dikira melalui fungsi fragmentation_index:

1. /*
2. \* Index is between 0 and 1000
3. *
4. \* 0 => allocation would fail due to lack of memory
5. \* 1000 => allocation would fail due to fragmentation
6. */
7. return 1000 - div_u64( (1000+(div_u64(info->free_pages * 1000ULL, requested))), info->free_blocks_total)

Semasa proses menyatukan serpihan memori, halaman yang berpecah-belah hanya akan bergerak dalam zon ini, dan halaman yang terletak di alamat rendah dalam zon akan dialihkan ke hujung zon sebanyak mungkin. Memohon lokasi halaman baharu dilaksanakan melalui fungsi compaction_alloc.

Proses pergerakan dibahagikan kepada segerak dan tak segerak Selepas aplikasi memori gagal, padat pertama akan menggunakan tak segerak, dan tuntutan semula seterusnya akan menggunakan segerak. Proses segerak hanya mengalihkan halaman yang tidak digunakan pada masa ini, dan proses tak segerak akan merentasi dan menunggu semua halaman MOVable digunakan sebelum dialihkan.

2 Susun halaman mengikut mobiliti

Halaman ingatan dibahagikan kepada tiga jenis berikut mengikut mobiliti:
TIDAK BOLEH DIGERAK: Lokasi dalam ingatan adalah tetap dan tidak boleh dialihkan sesuka hati. Memori yang diperuntukkan oleh kernel pada asasnya tergolong dalam jenis ini;
BOLEH TUTUP SEMULA: Tidak boleh dialihkan, tetapi boleh dipadam dan dikitar semula. Contohnya, memori dipetakan fail;
MOVable: Ia boleh dialihkan sesuka hati memori ruang pengguna pada asasnya tergolong dalam jenis ini.
Apabila memohon memori, mula-mula memohon memori dalam halaman percuma jenis yang ditentukan mengikut mobiliti Memori bebas setiap zon disusun seperti berikut:

1. struct zone {
2. ......
3. struct free_area free_area[MAX_ORDER];
4. ......
5. }
6.  
7. struct free_area {
8. struct list_head free_list[MIGRATE_TYPES];
9. unsigned long nr_free;
10. };

Apabila memori tidak boleh digunakan dalam kawasan_bebas jenis yang ditentukan, ia boleh dialihkan daripada jenis sandaran Memori yang dialihkan akan dikeluarkan ke senarai jenis yang baru ditentukan Kernel memanggil proses ini "kecurian".
Senarai keutamaan jenis ganti ditakrifkan seperti berikut:

1. static int fallbacks[MIGRATE_TYPES][4] = {
2. [MIGRATE_UNMOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE, MIGRATE_RESERVE },
3. [MIGRATE_RECLAIMABLE] = { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, MIGRATE_RESERVE },
4. \#ifdef CONFIG_CMA
5. [MIGRATE_MOVABLE] = { MIGRATE_CMA, MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE },
6. [MIGRATE_CMA] = { MIGRATE_RESERVE }, /* Never used */
7. \#else
8. [MIGRATE_MOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_RESERVE },
9. \#endif
10. [MIGRATE_RESERVE] = { MIGRATE_RESERVE }, /* Never used */
11. \#ifdef CONFIG_MEMORY_ISOLATION
12. [MIGRATE_ISOLATE] = { MIGRATE_RESERVE }, /* Never used */
13. \#endif
14. };

Perlu diingat bahawa tidak semua senario sesuai untuk menyusun halaman mengikut mobiliti Apabila saiz memori tidak mencukupi untuk diperuntukkan kepada pelbagai jenis, ia tidak sesuai untuk membolehkan mobiliti. Terdapat pembolehubah global untuk menunjukkan sama ada ia didayakan, yang ditetapkan semasa permulaan memori:

1. void __ref build_all_zonelists(pg_data_t *pgdat, struct zone *zone)
2. {
3. ......
4. if (vm_total_pages else
7. page_group_by_mobility_disabled = 0;
8. ......
9. }

Jika page_group_by_mobility_disabled, semua memori tidak boleh dialihkan.
Terdapat parameter yang menentukan sekurang-kurangnya bilangan halaman setiap kawasan memori, pageblock_nr_pages, yang ditakrifkan seperti berikut:

#define pageblock_order HUGETLB_PAGE_ORDER

1. \#else /* CONFIG_HUGETLB_PAGE */
2. /* If huge pages are not used, group by MAX_ORDER_NR_PAGES */
3. \#define pageblock_order (MAX_ORDER-1)
4. \#endif /* CONFIG_HUGETLB_PAGE */
5. \#define pageblock_nr_pages (1UL 

Semasa permulaan sistem, semua halaman ditanda MOVable:

1. void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
2. unsigned long start_pfn, enum memmap_context context)
3. {
4. ......
5. if ((z->zone_start_pfn 

Jenis mobiliti halaman lain dijana kemudian, iaitu "mencuri" yang disebutkan di atas. Apabila ini berlaku, keutamaan yang lebih tinggi, halaman bersebelahan yang lebih besar dalam sandaran biasanya "dicuri" untuk mengelakkan penjanaan serpihan kecil.

1. /* Remove an element from the buddy allocator from the fallback list */
2. static inline struct page *
3. __rmqueue_fallback(struct zone *zone, int order, int start_migratetype)
4. {
5. ......
6. /* Find the largest possible block of pages in the other list */
7. for (current_order = MAX_ORDER-1; current_order >= order;
8. --current_order) {
9. for (i = 0;; i++) {
10. migratetype = fallbacks[start_migratetype][i];
11. ......
12. }

Anda boleh melihat pengedaran pelbagai jenis halaman dalam sistem semasa melalui /proc/pageteypeinfo.

3 Domain memori boleh alih maya

Sebelum teknologi menyusun halaman berdasarkan mobiliti, terdapat kaedah lain yang telah disepadukan ke dalam kernel, iaitu domain memori maya: ZONE_MOVABLE. Idea asasnya mudah: bahagikan memori kepada dua bahagian, boleh tanggal dan tidak boleh tanggal.

1. enum zone_type {
2. \#ifdef CONFIG_ZONE_DMA
3. ZONE_DMA,
4. \#endif
5. \#ifdef CONFIG_ZONE_DMA32
6. ZONE_DMA32,
7. \#endif
8. ZONE_NORMAL,
9. \#ifdef CONFIG_HIGHMEM
10. ZONE_HIGHMEM,
11. \#endif
12. ZONE_MOVABLE,
13. __MAX_NR_ZONES
14. };

ZONE_MOVABLE的启用需要指定kernel参数kernelcore或者movablecore,kernelcore用来指定不可移动的内存数量,movablecore指定可移动的内存大小,如果两个都指定,取不可移动内存数量较大的一个。如果都不指定,则不启动。
与其它内存域不同的是ZONE_MOVABLE不关联任何物理内存范围,该域的内存取自高端内存域或者普通内存域。
find_zone_movable_pfns_for_nodes用来计算每个node中ZONE_MOVABLE的内存数量,采用的内存区域通常是每个node的最高内存域,在函数find_usable_zone_for_movable中体现。
在对每个node分配ZONE_MOVABLE内存时,kernelcore会被平均分配到各个Node:
kernelcore_node = required_kernelcore / usable_nodes;
在kernel alloc page时,如果gfp_flag同时指定了__GFP_HIGHMEM和__GFP_MOVABLE,则会从ZONE_MOVABLE内存域申请内存。

总之,Linux kernel内存碎片防治技术是一个非常重要的概念,可以帮助你更好地理解Linux系统中的内存管理。如果你想了解更多关于这个概念的信息,可以查看本文提供的参考资料。

Atas ialah kandungan terperinci Teknologi pencegahan pemecahan memori kernel Linux: pemahaman mendalam tentang pengurusan memori. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:lxlinux.net. Jika ada pelanggaran, sila hubungi admin@php.cn Padam