Schauen wir uns die benutzerdefinierte zmalloc-Funktion im Redis-Quellcode an (nicht die neueste Version). Diese Funktion wird genauso verwendet wie reguläre Funktionen wie malloc. Der Unterschied liegt in den internen Implementierungsdetails.
void *zmalloc(size_t size) {
// Speicher zuweisen;
void *ptr = malloc(size + PREFIX_SIZE);
// Zuweisungsfehler löst Ausnahme aus;
If (!ptr) zmalloc_oom_handler(size);
// Kann das System die Funktion „malloc_size“ verwenden?
#ifdef HAVE_MALLOC_SIZE
Update_zmalloc_stat_alloc(zmalloc_size(ptr));
Return ptr;
#else
//Speichern Sie die tatsächliche Größe der zugewiesenen Daten im Datenfeld. *((size_t*)ptr) = size;
// Berechnen Sie die Speichernutzung nach der Ausrichtung und aktualisieren Sie die Variable „used_memory“
Update_zmalloc_stat_alloc(size + PREFIX_SIZE);
// Die Anfangsposition des Datenkörpers zurückgeben;
Return (char*)ptr + PREFIX_SIZE;
#endif
}
Tatsächlich kann die Malloc-Funktion in der Standardbibliothek den zugewiesenen Speicher bereits automatisch ausrichten. Daher besteht der Hauptzweck der Zmalloc-Methode hier darin, die für jeden Datenspeicher zugewiesene Speichergröße genau zu berechnen. Jedes Mal, wenn Speicher zugewiesen wird, fügt zmalloc der zugewiesenen Datenspeichergröße einen zusätzlichen Speicherplatz hinzu. Dieses PREFIX_SIZE-Makro stellt die maximale Speicheradressierungsraumgröße (size_t) des aktuellen Systems dar. Hier können wir diesen PREFIX_SIZE-Größenraum als „Datenheader“-Teil einer Speichereinheit bezeichnen.
Die Speichereinheitenstruktur der ersten Version von Redis
Wie in der Abbildung oben gezeigt, speichert Redis über die Anweisung *((size_t*)ptr) = size; die tatsächlich zugewiesene Datenblockgröße in den ersten PREFIX_SIZE-Bytes des aktuell zugewiesenen Speicherblocks, also im Datenheader. und im Folgenden werden Binärdatenentitäten tatsächlich im Speicherplatz der Größe „Größe“ gespeichert. Die Funktion namens update_zmalloc_stat_alloc verwaltet hier intern eine globale Variable namens used_memory, die jedes Mal die neu zugewiesene Speichergröße akkumuliert. Die Funktion gibt am Ende einen Offset-Zeiger zurück, der auf den Datenkörperteil des aktuell zugewiesenen Speichers zeigt. Die spezifischen Implementierungsdetails der Funktion update_zmalloc_stat_alloc lauten wie folgt.
#define update_zmalloc_stat_alloc(__n) do {
size_t _n = (__n);
// Manuelles Füllen des Speichers; If (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); atomicIncr(used_memory, __n);
} while(0)
Wichtig ist hier die Zeile _n += sizeof(long)-(_n&(sizeof(long)-1));. Die gesamte Makrofunktion bestimmt zunächst, ob die diesmal zugewiesene Speichergröße ein ganzzahliges Vielfaches von sizeof(long) ist (64-Bit-Maschinen entsprechen einer 8-Byte-Speicherausrichtung; 32-Bit-Maschinen entsprechen einer 4-Byte-Speicherausrichtung), wenn nicht Verwenden Sie dann die Anweisung, die wir zuvor gegeben haben, um den entsprechenden Platzhalterraum nach dem Datensegment hinzuzufügen, um die Anzahl der Bits zu erreichen, die den Speicherausrichtungsanforderungen (4/8 Bytes) entspricht. Die letzte Funktion „atomicIncr“ wird verwendet, um den globalen Variablenwert „used_memory“ zu aktualisieren und gleichzeitig die Thread-Sicherheit sicherzustellen.
Der Prozess der Speicherfreigabe und Speicherzuweisung ist in dieser Version von Redis genau umgekehrt. Der unten gezeigte Code enthält die Implementierungsdetails der entsprechenden „zfree“-Funktion. Zuerst zeigt die Funktion über die Anweisung (char*)ptr-PREFIX_SIZE auf die erste Adresse des Datenfelds, das die tatsächliche Größe des Datenblocks enthält (und wechselt zu einer niedrigeren Speicheradresse) und ruft dann die Daten über *(( size_t*)realptr)-Anweisung. Die tatsächliche vom Block zugewiesene Speichergröße (ohne Speicherausrichtungsbereiche). Aktualisieren Sie abschließend den Wert der globalen Variablen used_memory über die Funktion update_zmalloc_stat_free und geben Sie das Speichersegment frei.
void zfree(void *ptr) {
#ifndef HAVE_MALLOC_SIZE
void *realptr;
size_t oldsize;
#endif
If (ptr == NULL) return;
#ifdef HAVE_MALLOC_SIZE
Update_zmalloc_stat_free(zmalloc_size(ptr));
kostenlos(ptr);
#else
realptr = (char*)ptr-PREFIX_SIZE;
Oldsize = *((size_t*)realptr);
Update_zmalloc_stat_free(oldsize+PREFIX_SIZE);
free(realptr);
#endif
}
Wenn wir uns hier die Implementierungsdetails der Funktion update_zmalloc_stat_free ansehen, werden Sie, wie unten gezeigt, feststellen, dass sie dem Ausführungsprozess der vorherigen Funktion update_zmalloc_stat_alloc ähnelt. Durch Berechnen der Größe der Speicherbytes, die ergänzt werden müssen, und Subtrahieren der entsprechenden Größe des Speicherplatzes von der Variablen used_memory kann die Speicherplatznutzung genau berechnet werden.
#define update_zmalloc_stat_free(__n) do {
size_t _n = (__n);
If (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); atomicDecr(used_memory,__n);
} while(0)
Das obige ist der detaillierte Inhalt vonBeispielanalyse der Redis-Zmalloc-Funktion. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!