Heim  >  Artikel  >  Backend-Entwicklung  >  Vertiefendes Verständnis der Nginx-Speicherverwaltung (Bild)

Vertiefendes Verständnis der Nginx-Speicherverwaltung (Bild)

不言
不言nach vorne
2018-11-15 17:14:533670Durchsuche

Dieser Artikel vermittelt Ihnen ein tiefgreifendes Verständnis der Speicherverwaltung von Nginx (Bilder). Ich hoffe, dass er Ihnen als Referenz dienen wird.

1. Übersicht

  1. Der Speicher der Anwendung kann einfach in Heap-Speicher und Stapelspeicher unterteilt werden. Für den Stapelspeicher fügt der Compiler beim Kompilieren einer Funktion Code ein, der die aktuelle Zeigerposition des Stapels verschiebt, um eine Selbstverwaltung des Stapelspeichers zu realisieren. Für den Heap-Speicher müssen Programmierer ihn normalerweise verwalten. Die Speicherverwaltung, über die wir normalerweise sprechen, ist nur die Heap-Space-Speicherverwaltung.

  2. Für den Speicher kann unsere Verwendung in drei Schritte vereinfacht werden: Speicher beantragen, Speicher verwenden und Speicher freigeben. Die Beantragung von Speicher und die Verwendung von Speicher erfordern normalerweise explizite Vorgänge durch Programmierer, aber die Freigabe von Speicher erfordert nicht unbedingt explizite Vorgänge durch Programmierer. Derzeit bieten viele Hochsprachen Mechanismen zur Speicherbereinigung, und Sie können den Zeitpunkt für die Speicherfreigabe auswählen Beispiel: Go und Java haben die Garbage Collection implementiert, die C-Sprache hat die Garbage Collection noch nicht implementiert. In C++ kann die Garbage Collection durch intelligente Zeiger erreicht werden.

  3. Zusätzlich zur Speicherverwaltung auf Sprachebene müssen wir den Speicher manchmal selbst im Programm verwalten. Im Allgemeinen geht es bei der Speicherverwaltung meiner Meinung nach hauptsächlich darum, die folgenden Probleme zu lösen :

  • Wie kann ein Benutzer schnell den Speicherblock finden, der den Anforderungen des Benutzers entspricht, wenn er sich um Arbeitsspeicher bewirbt?

  • Wie kann eine Speicherfragmentierung vermieden werden, wenn Benutzer Speicher freigeben?

Ob es sich um eine auf Sprachebene implementierte Speicherverwaltung oder eine von der Anwendung selbst implementierte Speicherverwaltung handelt, der meiste Speicher ist je nach Größe in mehrere Typen unterteilt, die jeweils einen anderen Verwaltungsmodus verwenden. Eine übliche Klassifizierung besteht darin, verschiedene Speichertypen durch verknüpfte Listen in Ganzzahlpotenzen zu unterteilen. Wenn Sie sie nicht finden können, können Sie einen Teil aus einem größeren Speicherblock verwenden. Teilen Sie es in mehrere kleine Speicherpunkte auf. Bei besonders großen Speichern kann die Speicherverwaltung auf Sprachebene natürlich direkt speicherverwaltungsbezogene Systemaufrufe aufrufen, und die Speicherverwaltung auf Anwendungsebene kann die Speicherverwaltung auf Sprachebene direkt aufrufen.

  1. Die Nginx-Speicherverwaltung als Ganzes kann in zwei Teile unterteilt werden:

  • Der erste Teil ist der herkömmliche Speicher Pool, mit der für den Prozess erforderlichen Speicherverwaltung;

  • Der zweite Teil ist die Verwaltung des gemeinsam genutzten Speichers. Insgesamt ist Shared Memory deutlich komplexer als Memory Pools.

2. Nginx-Speicherpoolverwaltung

2.1 Beschreibung

  1. Die in diesem Teil verwendete Nginx-Version ist 1.15.3

  2. Den spezifischen Quellcode finden Sie in der Datei src/core/ngx_palloc.c

2.2 Nginx-Implementierung

2.2.1 Nutzungsprozess

Die Nutzung des Nginx-Speicherpools ist relativ einfach und kann in 3 Schritte unterteilt werden

  • Rufen Sie die Funktion ngx_create_pool auf. Rufen Sie den Zeiger ngx_pool_t ab.

//size代表ngx_pool_t一块的大小
ngx_pool_t* ngx_create_pool(size_t size, ngx_log_t *log)
  • Rufen Sie ngx_palloc an, um die Speichernutzung zu beantragen

//从pool中申请size大小的内存
void* ngx_palloc(ngx_pool_t *pool, size_t size)
  • Speicher freigeben (kann freigegeben werden großer Blockspeicher oder Freigabe des gesamten Speicherpools)

//释放从pool中申请的大块内存
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p)
//释放整个内存池
void ngx_destroy_pool(ngx_pool_t *pool)

2.2.2 Spezifische Implementierung

  1. Wie in der Abbildung unten gezeigt, teilt Nginx den Speicher auf In zwei Typen einteilen: Einer ist kleiner Speicher und der andere ist großer Speicher. Wenn der angewendete Speicherplatz größer als pool->max ist, betrachten wir ihn als großen Speicherplatz, andernfalls handelt es sich um kleinen Speicherplatz.

//创建内存池的参数size减去头部管理结构ngx_pool_t的大小
pool->max = size - sizeof(ngx_pool_t);

Vertiefendes Verständnis der Nginx-Speicherverwaltung (Bild)

Bei einem kleinen Speicherplatz prüft Nginx zunächst, ob der im aktuellen Speicherblock zuzuweisende Speicherplatz den Anforderungen des Benutzers entsprechen kann , dann Geben Sie diesen Teil des Speichers direkt zurück. Wenn die Anforderungen des Benutzers nicht erfüllt werden können, müssen Sie einen erneuten Antrag auf einen Speicherblock stellen. Der beantragte Speicherblock hat die gleiche Größe wie der aktuelle Blockplatz. Der neu beantragte Speicherblock ist über a mit dem vorherigen Speicherblock verknüpft verknüpfte Liste, und der vom Benutzer benötigte Speicherblock wird aus dem neuen Speicherblock zugewiesen.

Kleiner Speicher wird nicht direkt nach der Anwendung freigegeben. Auch wenn er später nicht mehr verwendet wird, besteht keine Notwendigkeit, den Speicher freizugeben. Da Benutzer manchmal nicht wissen, ob der von ihnen verwendete Speicherblock groß oder klein ist, können sie auch die Funktion ngx_pfree aufrufen, um den Speicherplatz freizugeben. Diese Funktion sucht nach Speicher in der verknüpften Liste mit großem Speicherplatz und gibt den Speicher frei, wenn er gefunden wird . Bei kleinem Speicher erfolgt keine Verarbeitung.

Große Speicherblöcke speichert Nginx in verknüpften Listen und verwaltet sie über pool->large. Es ist zu beachten, dass die ngx_pool_large_t-Struktur für benutzerverwalteten großen Speicher aus einem kleinen Speicherblock in diesem Speicherpool angewendet wird, was bedeutet, dass diese Speicher nicht direkt von nginx wiederverwendet werden können. Wenn Benutzer einen großen Speicherplatz beantragen müssen, verwenden sie die C-Funktionsbibliothek malloc, um Speicherplatz zu beantragen, und mounten ihn dann in einer bestimmten ngx_pool_large_t-Struktur. Wenn nginx eine neue ngx_pool_large_t-Struktur benötigt, überprüft es zunächst die ersten drei Elemente der pool->large-verknüpften Liste, um festzustellen, ob eines verfügbar ist. Andernfalls wird ein neues ngx_pool_large_t erstellt Struktur.

3. Nginx-Shared-Memory-Verwaltung

3.1 Beschreibung

  1. Die hier verwendete Nginx-Version Teil Es ist 1.15.3

  2. Einzelheiten zum Quellcode dieses Teils finden Sie unter src/core/ngx_slab.c, src/core/ngx_shmtx.c

  3. Nginx-Freigabe Der Speicherinhalt ist relativ groß, daher gibt dieser Artikel nur einen kurzen Überblick.

3.2 Direkte Nutzung des Shared Memory

3.2.1 Grundlagen

  1. Es muss ein erstellt werden Interaktive Schnittstelle in Nginx. Die Ausschlusssperre wird für die spätere Synchronisierung mehrerer Prozesse verwendet. Darüber hinaus benötigt Nginx möglicherweise einige statistische Informationen, z. B. Einstellungen (stat_stub). Wir müssen diese Variablen nur öffnen und direkt verwenden.

  2. Die nach dem Festlegen von stat_stub erforderlichen statistischen Informationen werden ebenfalls im gemeinsamen Speicher abgelegt. Zur Erläuterung verwenden wir hier nur die Mutex-Sperre in Nginx.

3.2.2 Implementierung der Nginx-Mutex-Sperre

  1. Nginx-Mutex-Sperre: Wenn das System atomare Operationen unterstützt, gibt es zwei Lösungen werden verwendet, und Dateisperren werden verwendet, wenn sie nicht unterstützt werden. Den Quellcode dieses Abschnitts finden Sie in der Funktion ngx_event_module_init.

  2. Die folgende Abbildung ist ein schematisches Diagramm einer Dateisperre, die eine gegenseitige Ausschlusssperre implementiert.

Vertiefendes Verständnis der Nginx-Speicherverwaltung (Bild)

  1. Die folgende Abbildung ist ein schematisches Diagramm der atomaren Operation zur Implementierung einer Mutex-Sperre.

Vertiefendes Verständnis der Nginx-Speicherverwaltung (Bild)

  1. Problem

Beim Neuladen fordert der neu gestartete Master den alten an 1 Der Master wird direkt nach dem Senden des Signals beendet. Der alte Master lädt die Konfiguration neu (ngx_init_cycle-Funktion) und erstellt einen neuen Worker-Prozess. Der neue Worker-Prozess verwendet dieselbe Sperre wie der alte Worker-Prozess.

Während eines reibungslosen Upgrades erstellt der alte Master einen neuen Master, und der neue Master erbt den Abhörport des alten Masters (der dem Abhör-Socket entsprechende fd wird über die Umgebungsvariable übergeben) und der Der neue Prozess wird nicht neu gestartet. Es kann Situationen geben, in denen neue und alte Worker gleichzeitig auf einen bestimmten Port lauschen. In diesem Fall stellt das Betriebssystem sicher, dass nur ein Prozess das Ereignis verarbeitet (obwohl epoll_wait aktiviert wird).

3.3 Gemeinsamen Speicher über Slab verwalten

  1. nginx ermöglicht es jedem Modul, gemeinsam genutzten Raum zur Nutzung zu öffnen, wie zum Beispiel das Modul ngx_http_limit_conn_module.

  2. Die Grundideen der gemeinsamen Speicherverwaltung von Nginx sind:

1. Ordnen Sie Speicher nach Seiten zu, und die Größe jeder Seite beträgt Dasselbe, hier auf page_size setzen.

2. Teilen Sie den Speicherblock entsprechend der ganzzahligen Potenz von 2. Das Minimum ist 8 Bit und das Maximum ist page_size/2. Unter der Annahme, dass die Größe jeder Seite beispielsweise 4 KB beträgt, ist der Speicher in 9 Typen unterteilt: 8, 16, 32, 64, 128, 256, 512, 1024, 2048, die jeweils einem Steckplatz entsprechen Größe n des Slot-Arrays beträgt 9. Wenn Sie einen kleinen Speicherblock beantragen (Speichergröße

3. Jede Seite wird nur in einen Speicherblocktyp unterteilt. Wenn Sie beispielsweise Speicher beantragen, kann der vorhandene Speicher die Anforderungen nicht erfüllen. Zu diesem Zeitpunkt wird eine neue Seite verwendet, und diese neue Seite wird in Zukunft nur noch Speicher dieser Größe zuweisen.

4. Verbinden Sie alle kostenlosen Seiten über eine doppelt verknüpfte Liste. Die freie Variable in ngx_slab_pool_t in der Abbildung wird zum Verknüpfen freier Seiten verwendet.

5. Verknüpfen Sie die von allen kleinen Speicherblöcken verwendeten Seiten über das Slots-Array.

6. Berechnen Sie bei Platzanfragen, die größer oder gleich der Seitengröße sind, die Anzahl der erforderlichen Seiten, suchen Sie nach fortlaufenden freien Seiten, geben Sie die Homepage-Adresse der freien Seite an den Kunden zurück und identifizieren Sie sie über die Verwaltungsstruktur ngx_slab_page_t jeder Seite.

7. Alle Seiten haben nur 3 Status: frei, nicht voll und voll. Freie und nicht vollständige Seiten werden über eine bidirektionale verknüpfte Liste integriert. Vollständige Seiten sind bei keiner Seite vorhanden. Wenn der Speicherplatz freigegeben wird, wird er einer verknüpften Liste hinzugefügt.

  1. Das Grundstrukturdiagramm des gemeinsam genutzten Nginx-Speichers lautet wie folgt:

Vertiefendes Verständnis der Nginx-Speicherverwaltung (Bild)

  • Im obigen Bild sind andere Speicher, mit Ausnahme eines Speicherabschnitts, der an der ngx_slab_pool_t-Schnittstelle ganz rechts beginnt und sich im Shared-Memory-Bereich befindet, kein Shared-Memory.

  • Gemeinsamer Speicher wird letztendlich von der Seite zugewiesen.

Das obige ist der detaillierte Inhalt vonVertiefendes Verständnis der Nginx-Speicherverwaltung (Bild). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

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