Heim  >  Artikel  >  System-Tutorial  >  Technologie zur Verhinderung der Fragmentierung des Linux-Kernel-Speicherfragments: Vertiefendes Verständnis der Speicherverwaltung

Technologie zur Verhinderung der Fragmentierung des Linux-Kernel-Speicherfragments: Vertiefendes Verständnis der Speicherverwaltung

WBOY
WBOYnach vorne
2024-02-12 09:54:15834Durchsuche

Sind Sie schon einmal auf verschiedene Speicherprobleme in Linux-Systemen gestoßen? Wie Speicherlecks, Speicherfragmentierung usw. Diese Probleme können durch ein umfassendes Verständnis der Technologie zur Verhinderung der Speicherfragmentierung des Linux-Kernels gelöst werden.

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

Die Art und Weise, wie der Linux-Kernel den physischen Speicher organisiert und verwaltet, ist eine der Schwächen des Buddy-Systems. Um das Fragmentierungsproblem zu verhindern und zu lösen, hat der Kernel einige praktische Technologien übernommen wird hier zusammengefasst.

1 Fragmente konsolidieren, wenn der Speicher knapp wird

Speicherseiten von Buddy anwenden Wenn keine passende Seite gefunden wird, werden zwei Schritte der Speicheranpassung durchgeführt: Komprimieren und Zurückfordern. Ersteres besteht darin, Fragmente zu konsolidieren, um einen größeren zusammenhängenden Speicher zu erhalten. Letzteres besteht darin, Pufferspeicher wiederzuverwenden, der nicht unbedingt Speicher belegt. Der Fokus liegt hier darauf, kompakt zu verstehen. Der gesamte Prozess ist ungefähr wie folgt:

__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 und __GFP_IO; Darüber hinaus muss der verbleibende Speicher der Zone bestimmte Bedingungen erfüllen. Der Kernel nennt ihn „Fragmentierungsindex“. Die Komprimierung kann nur durchgeführt werden, wenn der Standard-Fragmentierungsindex größer ist als 500. Dieser Standardwert kann über die Proc-Datei extfrag_threshold angepasst werden. Der Fragmentierungsindex wird über die Funktion fragmentation_index berechnet:

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)

Während des Prozesses der Konsolidierung von Speicherfragmenten werden fragmentierte Seiten nur innerhalb dieser Zone verschoben und Seiten, die sich an niedrigen Adressen in der Zone befinden, werden so weit wie möglich an das Ende der Zone verschoben. Die Beantragung eines neuen Seitenstandorts wird über die Funktion „compaction_alloc“ implementiert.

Der Bewegungsprozess ist in synchrone und asynchrone Prozesse unterteilt. Nachdem die Speicheranwendung fehlgeschlagen ist, wird bei der ersten Komprimierung die asynchrone Funktion und bei der anschließenden Wiederherstellung die synchrone Funktion verwendet. Der synchrone Prozess verschiebt nur die Seiten, die derzeit nicht verwendet werden, und der asynchrone Prozess durchläuft alle beweglichen Seiten und wartet darauf, dass sie verwendet werden, bevor er verschoben wird.

2 Seiten nach Mobilität organisieren

Speicherseiten werden je nach Mobilität in die folgenden drei Typen unterteilt:
UNVERSCHIEBBAR: Der Speicherort ist fest und kann nicht beliebig verschoben werden. Der vom Kernel zugewiesene Speicher gehört grundsätzlich zu diesem Typ;
WIEDERHERSTELLBAR: Kann nicht verschoben, aber gelöscht und recycelt werden. Zum Beispiel File Mapped Memory;
BEWEGLICH: Es kann grundsätzlich nach Belieben verschoben werden.
Wenn Sie Speicher beantragen, beantragen Sie zunächst Speicher in der angegebenen Art von freier Seite entsprechend der Mobilität. Der freie Speicher jeder Zone ist wie folgt organisiert:

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. };

Wenn der Speicher im Free_Area des angegebenen Typs nicht beantragt werden kann, kann er vom Sicherungstyp umgeleitet werden. Der umgeleitete Speicher wird in die neu angegebene Typliste freigegeben. Der Kernel nennt diesen Prozess „Diebstahl“.
Die Prioritätenliste für alternative Typen ist wie folgt definiert:

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. };

Es ist zu beachten, dass nicht alle Szenarien für die Organisation von Seiten nach Mobilität geeignet sind. Wenn die Speichergröße nicht ausreicht, um sie verschiedenen Typen zuzuweisen, ist sie nicht geeignet, Mobilität zu ermöglichen. Es gibt eine globale Variable, die angibt, ob sie aktiviert ist und die während der Speicherinitialisierung festgelegt wird:

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. }

Wenn page_group_by_mobility_disabled ist, ist der gesamte Speicher nicht verschiebbar.
Es gibt einen Parameter, der die Mindestanzahl an Seiten jedes Speicherbereichs bestimmt, pageblock_nr_pages, der wie folgt definiert ist:

#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 

Während der Systeminitialisierung werden alle Seiten mit MOVABLE:

markiert
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 

Andere Mobilitätstypen von Seiten werden später generiert, was dem oben erwähnten „Stehlen“ entspricht. Wenn dies geschieht, werden in der Regel größere zusammenhängende Seiten mit höherer Priorität im Fallback „gestohlen“, um die Erzeugung kleiner Fragmente zu vermeiden.

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. }

Sie können die Verteilung verschiedener Seitentypen im aktuellen System über /proc/pageteypeinfo überprüfen.

3 Virtuelle Wechselspeicherdomäne

Vor der Technologie zum Organisieren von Seiten basierend auf Mobilität gab es eine andere Methode, die in den Kernel integriert wurde, und zwar die virtuelle Speicherdomäne: ZONE_MOVABLE. Die Grundidee ist einfach: Teilen Sie den Speicher in zwei Teile, einen entfernbaren und einen nicht entfernbaren.

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系统中的内存管理。如果你想了解更多关于这个概念的信息,可以查看本文提供的参考资料。

Das obige ist der detaillierte Inhalt vonTechnologie zur Verhinderung der Fragmentierung des Linux-Kernel-Speicherfragments: Vertiefendes Verständnis der Speicherverwaltung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:lxlinux.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen