/********************** * Linux-Speicherverwaltung **************************/ Die Speicherverwaltung ist die mit Abstand komplexeste Aktivität im Unix-Kernel. Wir stellen kurz die Speicherverwaltung vor und veranschaulichen anhand von Beispielen, wie man im Kernelmodus Speicher erhält. (1) Verschiedene Adressen Bei x86-Prozessoren muss zwischen folgenden drei Adresstypen unterschieden werden: *Logische Adresse Es wird nur x86 unterstützt. Jede logische Adresse besteht aus einem Segment und einem Offset, der die Entfernung vom Segmentanfang bis zur eigentlichen Adresse angibt. Die logische Adresse beträgt 48 Bit, der Segmentselektor 16 Bit und der Offset 32 Bit. Linux bietet nur eingeschränkte Unterstützung für logische Adressen *Lineare Adresse Wird auch als virtuelle Adresse bezeichnet. Vorzeichenloser 32-Bit-Ganzzahlwert von 0x0000,0000 bis 0xffff,ffff, ein Gesamtadressbereich von 4 GB. Unabhängig davon, ob es sich um eine Anwendung oder einen Treiber handelt, sind die Adressen, die wir im Programm verwenden, virtuelle Adressen. * Physische Adresse Eine vorzeichenlose 32-Bit-Ganzzahl, die den elektrischen Signalen entspricht, die von den Adresspins der CPU an den Speicherbus gesendet werden. Wird zur Speicheradressierung verwendet. Suchen Sie ein Programm wie scanf.c, führen Sie es zweimal aus und befolgen Sie dann die folgenden Anweisungen zur Beobachtung: $>pmap $(pid) $>cat /proc/$(pid)/maps (2) Physischer Speicher und virtueller Speicher a. Physischer Speicher Es handelt sich um den RAM, der tatsächlich im System vorhanden ist, wie z. B. der 256 MB RAM, von dem wir oft sprechen. Der x86-Prozessor und der physische Speicher sind über tatsächliche physische Leitungen verbunden. Darüber hinaus ist der x86-Prozessor über die Hauptplatine mit vielen Peripheriegeräten verbunden, und diese Peripheriegeräte sind wiederum über tatsächliche physische Leitungen mit dem Prozessor verbunden. Für den Prozessor ist die Zugriffsmethode für die meisten Peripheriegeräte und den RAM dieselbe, d. h. das Programm gibt eine physische Adresse aus, um auf das tatsächliche physische Gerät zuzugreifen. Peripheriegeräte und RAM teilen sich einen physischen 4G-Speicherplatz. b. Virtueller Speicher Es handelt sich um einen logischen Speicher, der für jeden Prozess über dem physischen Speicher zwischen der Speicheranforderung der Anwendung und der Hardware-Speicherverwaltungseinheit (MMU) erstellt wird. Die MMU konvertiert den von der Anwendung verwendeten virtuellen Speicher gemäß einer vordefinierten Seitentabelle in physische Adressen und greift dann über die physischen Adressen auf die tatsächlichen Peripheriegeräte oder den RAM zu. Virtueller Speicher hat viele Einsatzmöglichkeiten und Vorteile:
(3) RAM-Nutzung Linux teilt den eigentlichen physischen RAM in zwei Teile. Mehrere Megabyte werden zum Speichern des Kernel-Images verwendet (also des Kernel-Codes und der statischen Kernel-Datenstrukturen). Der restliche RAM wird normalerweise vom virtuellen Speichersystem verwaltet und auf die folgenden drei Arten verwendet:
Eines der Hauptprobleme, mit denen sich der virtuelle Speicher befassen muss, ist die Speicherfragmentierung, da der Kernel normalerweise zusammenhängenden physischen Speicher verwendet und eine zu starke Fragmentierung daher zum Fehlschlagen von Anforderungen führen kann. /********************** * Speicher im Kernel abrufen************************/ Wie im Userspace kann Speicher im Kernel dynamisch zugewiesen und freigegeben werden, allerdings unterliegt er stärkeren Einschränkungen als im Userspace. (1) Speicherverwaltung im Kernel Der Kernel verwendet physische Seiten als Grundeinheit der Speicherverwaltung. Dies liegt hauptsächlich daran, dass die Speicherverwaltungseinheit (MMU) virtuelle Adressen und physische Adressen in Seiten umwandelt. Aus der Perspektive des virtuellen Speichers ist eine Seite die kleinste Einheit. Die meisten 32-Bit-Architekturen unterstützen 4-KB-Seiten. a. Seite Der Kernel verwendet die Strukturseite, um jede physische Seite im System darzustellen. Durch das Einbinden von <linux/mm.h> können Sie die Seite verwenden, die eigentlich in <linux/mm_types.h> definiert ist. Strukturseite{ page_flags_t-Flags; atomare_t_Anzahl; Atom_t_Mapanzahl; unsigniert, lange privat; Struktur Adressraum *Mapping; pgoff_t-Index; Struktur list_head lru; ungültig *virtuell; }; Flags werden verwendet, um den Status der Seite zu speichern, der in <linux/page-flags.h> definiert ist. Der Status umfasst, ob die Seite schmutzig ist, ob sie im Speicher gesperrt ist usw. _count speichert die Referenzanzahl der Seite. Die Seitenstruktur bezieht sich auf physische Seiten, nicht auf virtuelle Seiten. Der Zweck der Struktur besteht darin, den physischen Speicher selbst zu beschreiben, nicht die darin enthaltenen Daten. Der Kernel verwaltet alle Seiten im System basierend auf der Seitenstruktur. Über die Seite kann der Kernel erkennen, ob eine Seite frei ist (d. h. ob die Seite zugewiesen wurde). Wenn die Seite zugewiesen wurde, muss der Kernel auch wissen, wem die Seite gehört. Der Besitzer kann ein Userspace-Prozess, dynamisch zugewiesene Kerneldaten, statischer Kernelcode oder der Seitencache usw. sein. Eine solche Struktur wird jeder physischen Seite im System zugewiesen. Wenn die Struktur 40 Byte groß ist, muss 1 MB von 128 MB physischem Speicher (4-KB-Seiten) für die Seitenstruktur zugewiesen werden. b. Fläche Aufgrund von Hardwarebeschränkungen kann der Kernel nicht alle Seiten gleich behandeln. Der Kernel verwendet Zonen, um Seiten mit ähnlichen Eigenschaften zu gruppieren. Zu diesen Funktionen gehören:
Um diese Einschränkungen zu beheben, verwendet Linux drei Zonen (<linux/mmzone.h>):
Für x86 entspricht der physische Speicher diesen drei Bereichen:
Siehe Strukturzone in <linux/mmzone.h>. Es gibt im System nur drei solcher Zonenstrukturen. (2) Seitenzuordnung Der Kernel verwendet Seiten zur Speicherverwaltung, daher können wir das System auch auffordern, uns Speicher in Seiten im Kernel zuzuweisen. Natürlich kann die seitenweise Zuweisung zu Speicherverschwendung führen, daher rufen wir sie nur auf, wenn wir sicher sind, dass wir eine ganze Speicherseite benötigen. a. Zuordnung #include <linux/gfp.h> 1. Strukturseite * alloc_pages( vorzeichenlose int gfp_mask, vorzeichenlose int-Reihenfolge); //2 aufeinanderfolgende physische Seiten zuordnen. 2. void *Seitenadresse( Strukturseite *Seite); //Gibt einen Zeiger auf die aktuelle virtuelle Adresse einer bestimmten physischen Seite zurück 3. unsigned long __get_free_pages( vorzeichenlose int gfp_mask, vorzeichenlose int-Reihenfolge); //Entspricht der Kombination der beiden obigen Funktionen 4. struct page * alloc_page( vorzeichenlose int gfp_mask); 5. unsigned long __get_free_page( vorzeichenlose int gfp_mask); 6. unsigned long get_zeroed_page( vorzeichenlose int gfp_mask); //Nur eine Seite zuordnen b.gfp_mask-Flagge Dieses Flag bestimmt, wie sich der Kernel bei der Speicherzuweisung verhält und von wo aus er den Speicher zuweist. #include <linux/gfp.h> #GFP_ATOMIC definieren //Atomare Zuweisung, kein Ruhezustand, kann für die Interrupt-Verarbeitung verwendet werden. #define GFP_KERNEL //Bevorzugt, der Kernel kann schlafen, wird im Prozesskontext verwendet c. Release-Seite void __free_pages(Struktur Seite *Seite, vorzeichenlose int-Reihenfolge); void free_pages(unsigned long addr, vorzeichenlose int-Reihenfolge); void free_page(unsigned long addr); Beachten! Sie können nur Seiten freigeben, die Ihnen gehören. Falsche Parameter können einen Kernel-Panic verursachen. (3) Speicherbeschaffung über kmalloc kmalloc ist malloc sehr ähnlich und ist die am häufigsten verwendete Speicherzuweisungsfunktion im Kernel. kmalloc löscht den zugewiesenen Speicherbereich nicht auf 0 und der zugewiesene Bereich ist im physischen Speicher fortlaufend. a. Zuordnung #include <linux/slab.h> void *kmalloc(size_t Größe, int Flags) Größe ist die Größe des Speichers, der zugewiesen werden muss Der Flags-Parameter von kmalloc kann das Verhalten von kmalloc während der Zuweisung steuern. Die verwendeten Flags stimmen mit denen in alloc_page verwendeten überein. Beachten Sie, dass kmalloc keinen High-End-Speicher zuordnen kann. b. Freigabe #include <linux/slab.h> void kfree(const void *ptr); Dies kann schwerwiegende Folgen haben, wenn der freigegebene Speicher bereits freigegeben wurde oder wenn Speicher freigegeben wird, der zu anderen Teilen des Kernels gehört. Es ist sicher, kfree(NULL) aufzurufen. Seien Sie vorsichtig! Der Kernel kann nur Byte-Arrays einer vordefinierten, festen Größe zuordnen. Der kleinste Speicherblock, den kmalloc verarbeiten kann, ist 32 oder 64. Da der von kmalloc zugewiesene Speicher physisch kontinuierlich ist, gibt es eine Obergrenze für die Zuweisung, die normalerweise 128 KB nicht überschreiten sollte. (4) Speicher über vmalloc abrufen Die virtuellen Adressen des von vmalloc() zugewiesenen Speichers sind kontinuierlich, die physischen Adressen müssen jedoch nicht kontinuierlich sein. Dies ist auch die Art und Weise, wie malloc() zuweist. vmalloc weist nicht zusammenhängende Speicherblöcke zu und ändert dann die Seitentabelle, um den Speicher in einem zusammenhängenden Bereich im logischen Raum abzubilden. In den meisten Fällen müssen nur Hardwaregeräte Speicher mit kontinuierlichen physischen Adressen erhalten, und der Kernel kann den über vmalloc erhaltenen Speicher verwenden. Allerdings wird kmalloc hauptsächlich aus Leistungsgründen im Kernel verwendet, da vmalloc zu starkem TLB-Jitter führt, es sei denn, vmalloc wird beim Zuordnen großer Speicherblöcke verwendet. Wenn beispielsweise ein Modul dynamisch geladen wird, wird es in den von vmalloc zugewiesenen Speicher geladen. vmalloc wird in <linux/vmalloc.h> deklariert und in <mm/vmalloc.c> definiert. Die Verwendung ist dieselbe wie bei malloc(). void*vmalloc(vorzeichenlose lange Größe); void vfree(void *Adresse); vmalloc führt zum Ruhezustand (5) Speicherbeschaffung durch den Slab-Mechanismus Das Zuweisen und Freigeben von Datenstrukturen ist eine der häufigsten Operationen im Kernel. Eine gängige Methode besteht darin, eine freie Liste zu erstellen, die die zugewiesenen, zur Verwendung verfügbaren Datenstrukturblöcke enthält. Sie müssen nicht jedes Mal, wenn Sie eine Datenstruktur zuordnen müssen, erneut Speicher beantragen. Stattdessen können Sie den Datenblock direkt aus dieser freien verknüpften Liste zuordnen und den Speicher beim Freigeben der Struktur an diese verknüpfte Liste zurückgeben. Dabei handelt es sich eigentlich um eine Art Objekt-Cache (Zwischenspeichern von Objekten). Linux bietet einen Slab-Allocator, um diese Aufgabe zu erfüllen. Der Slab-Allocator sucht nach einem Gleichgewicht zwischen mehreren Grundprinzipien:
kmalloc wird auf der Platte aufgebaut. a. Einen neuen Cache erstellen #include <linux/slab.h> Struktur kmem_cache *kmem_cache_create( const char *Name, size_t Größe, size_t ausrichten, unsignierte lange Flags, void(*ctor)(...));
b. Zerstöre den Cache #include <linux/slab.h> void kmem_cache_destroy(struct kmem_cache *cachep); Diese Methode muss aufgerufen werden, nachdem alle Objekte im Cache freigegeben wurden. c. Holen Sie das Objekt aus dem Cache ungültig *kmem_cache_alloc( Struktur kmem_cache *cachep, int flags); Flaggen: GFP_KERNEL d. Geben Sie das Objekt wieder in den Cache frei. ungültig kmem_cache_free( Struktur kmem_cache *cachep, void *objp); Siehe kernel/fork.c (6) Zuordnung von High-End-Speicher Seiten im oberen Speicherbereich können nicht dauerhaft in den Kernel-Adressraum abgebildet werden. Daher können Seiten, die durch alloc_pages() mit dem Flag __GFP_HIGHMEM abgerufen werden, keine virtuellen Adressen haben. Es muss dynamisch über eine Funktion zugewiesen werden. a. Zuordnung Um eine gegebene Seitenstruktur in den Kernel-Adressraum abzubilden, verwenden Sie: void *kmap(Struktur Seite *Seite); Funktionen können schlafen b. Zuordnung aufheben void kunmap(Struktur Seite*Seite); Zusammenfassen Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, dass der Inhalt dieses Artikels einen gewissen Lernwert für Ihr Studium oder Ihre Arbeit hat. Vielen Dank für Ihre Unterstützung von 123WORDPRESS.COM. Wenn Sie mehr darüber erfahren möchten, schauen Sie sich bitte die folgenden Links an Das könnte Sie auch interessieren:
|
<<: Detaillierte Erklärung zum Remotezugriff auf die MySQL-Datenbank über Workbench
>>: Get/Delete-Methode zum Übergeben von Array-Parametern in Vue
Es gibt viele Gründe für den Export von MySQL-Dat...
1. Befehlseinführung Der Befehl ifconfig (Netzwer...
Inhaltsverzeichnis 1. Planaufgaben anpassen 2. Ze...
So installieren und konfigurieren Sie mysql-5.7.5...
Vim ist ein leistungsstarker Vollbild-Texteditor ...
Nachdem ich einige Artikel gelesen hatte, habe ic...
Ich habe vor Kurzem in einer neuen Firma angefang...
1. Laden Sie das Tomcat-Image herunter Docker zie...
1. Entpacken Sie das komprimierte MySQL-Paket in ...
Lassen Sie mich Ihnen zuerst das Effektbild zeige...
1: Tag-Selektor Der Tag-Selektor wird für alle Ta...
Installieren Sie CentOS 7 nach der Installation v...
Als Root-Konto von MySQL verwende ich beim Verbin...
Inhaltsverzeichnis Spielautomaten Was sind Slots?...
In diesem Artikelbeispiel wird der spezifische Co...