Wie funktionieren malloc () und free ()?


276

Ich möchte wissen wie mallocund freearbeiten.

int main() {
    unsigned char *p = (unsigned char*)malloc(4*sizeof(unsigned char));
    memset(p,0,4);
    strcpy((char*)p,"abcdabcd"); // **deliberately storing 8bytes**
    cout << p;
    free(p); // Obvious Crash, but I need how it works and why crash.
    cout << p;
    return 0;
}

Ich wäre wirklich dankbar, wenn die Antwort auf Speicherebene ausführlich wäre, wenn es möglich ist.


5
Sollte es nicht tatsächlich vom Compiler und der verwendeten Laufzeitbibliothek abhängen?
Vilx

9
Dies hängt von der CRT-Implementierung ab. Sie können es also nicht verallgemeinern.
Naveen

58
dieser strcpy schreibt 9 Bytes, nicht 8. Vergiss den NULL-Terminator nicht ;-).
Evan Teran


2
@ LưuVĩnhPhúc das ist C ++. Beachten Sie diecout <<
Braden Best

Antworten:


385

OK, einige Antworten zu malloc wurden bereits veröffentlicht.

Der interessantere Teil ist, wie frei funktioniert (und in dieser Richtung kann auch Malloc besser verstanden werden).

In vielen malloc / free-Implementierungen gibt free normalerweise den Speicher nicht an das Betriebssystem zurück (oder zumindest nur in seltenen Fällen). Der Grund ist, dass Sie Lücken in Ihrem Heap bekommen und es daher vorkommen kann, dass Sie nur Ihre 2 oder 4 GB virtuellen Speicher mit Lücken fertigstellen. Dies sollte vermieden werden, da Sie, sobald der virtuelle Speicher fertig ist, in große Schwierigkeiten geraten. Der andere Grund ist, dass das Betriebssystem nur Speicherblöcke verarbeiten kann, die eine bestimmte Größe und Ausrichtung haben. Um genau zu sein: Normalerweise kann das Betriebssystem nur Blöcke verarbeiten, die der virtuelle Speichermanager verarbeiten kann (meistens Vielfache von 512 Bytes, z. B. 4 KB).

Die Rückgabe von 40 Bytes an das Betriebssystem funktioniert also einfach nicht. Was macht Free?

Free setzt den Speicherblock in eine eigene freie Blockliste. Normalerweise wird auch versucht, benachbarte Blöcke im Adressraum miteinander zu verschmelzen. Die freie Blockliste ist nur eine kreisförmige Liste von Speicherblöcken, die am Anfang einige Verwaltungsdaten enthalten. Dies ist auch der Grund, warum die Verwaltung sehr kleiner Speicherelemente mit dem Standard malloc / free nicht effizient ist. Jeder Speicherblock benötigt zusätzliche Daten und bei kleineren Größen tritt eine stärkere Fragmentierung auf.

Die freie Liste ist auch der erste Ort, den Malloc betrachtet, wenn ein neuer Speicherblock benötigt wird. Es wird gescannt, bevor es neuen Speicher vom Betriebssystem anfordert. Wenn ein Block gefunden wird, der größer als der benötigte Speicher ist, wird er in zwei Teile geteilt. Einer wird an den Anrufer zurückgegeben, der andere wird wieder in die kostenlose Liste aufgenommen.

Es gibt viele verschiedene Optimierungen für dieses Standardverhalten (z. B. für kleine Speicherblöcke). Aber da malloc und free so universell sein müssen, ist das Standardverhalten immer der Fallback, wenn Alternativen nicht verwendbar sind. Es gibt auch Optimierungen bei der Handhabung der freien Liste - zum Beispiel das Speichern der Chunks in Listen, die nach Größen sortiert sind. Alle Optimierungen haben aber auch ihre eigenen Grenzen.

Warum stürzt Ihr Code ab:

Der Grund dafür ist, dass Sie durch Schreiben von 9 Zeichen (vergessen Sie nicht das nachfolgende Null-Byte) in einen Bereich mit einer Größe von 4 Zeichen wahrscheinlich die Verwaltungsdaten überschreiben, die für einen anderen Speicherblock gespeichert sind, der sich "hinter" Ihrem Datenblock befindet ( da diese Daten meistens "vor" den Speicherblöcken gespeichert werden). Wenn free dann versucht, Ihren Chunk in die freie Liste aufzunehmen, kann es diese Verwaltungsdaten berühren und daher über einen überschriebenen Zeiger stolpern. Dies wird das System zum Absturz bringen.

Dies ist ein ziemlich anmutiges Verhalten. Ich habe auch Situationen gesehen, in denen ein außer Kontrolle geratener Zeiger irgendwo Daten in der speicherfreien Liste überschrieben hat und das System nicht sofort abstürzte, sondern einige Unterprogramme später. Selbst in einem System mittlerer Komplexität können solche Probleme sehr, sehr schwer zu debuggen sein! In dem einen Fall, in dem ich involviert war, haben wir (eine größere Gruppe von Entwicklern) mehrere Tage gebraucht, um den Grund für den Absturz zu finden - da er sich an einem völlig anderen Ort befand als dem, der durch den Speicherauszug angegeben wurde. Es ist wie eine Zeitbombe. Sie wissen, Ihr nächstes "freies" oder "malloc" wird abstürzen, aber Sie wissen nicht warum!

Dies sind einige der schlimmsten C / C ++ - Probleme und ein Grund, warum Zeiger so problematisch sein können.


62
Soooo viele Leute wissen nicht, dass free () möglicherweise keinen Speicher an das Betriebssystem zurückgibt, es ist ärgerlich. Danke, dass du geholfen hast, sie aufzuklären.
Artelius

Artelius: Im Gegenteil, neuer Wille immer?
Guillaume07

3
@ Guillaume07 Ich nehme an, Sie meinten löschen, nicht neu. Nein, das tut es nicht (unbedingt). Löschen und Frei machen (fast) das Gleiche. Hier ist der Code, den jeder in MSVC2013 aufruft: goo.gl/3O2Kyu
Yay295

1
delete ruft immer den Destruktor auf, aber der Speicher selbst kann zur späteren Zuordnung auf eine freie Liste gesetzt werden. Abhängig von der Implementierung kann es sich sogar um dieselbe freie Liste handeln, die malloc verwendet.
David C.

1
@Juergen Aber wenn free () ein zusätzliches Byte liest, das Informationen darüber enthält, wie viel Speicher von malloc zugewiesen wurde, erhält es 4. Wie kam es dann zum Absturz oder wie free () berührt Verwaltungsdaten?
Undefiniertes Verhalten

56

Wie Aluser in diesem Forenthread sagt :

Ihr Prozess verfügt über einen Speicherbereich von Adresse x bis Adresse y, der als Heap bezeichnet wird. Alle Ihre malloc'd Daten leben in diesem Bereich. malloc () behält eine Datenstruktur, sagen wir eine Liste, aller freien Speicherplätze im Heap bei. Wenn Sie malloc aufrufen, durchsucht es die Liste nach einem Block, der groß genug für Sie ist, gibt einen Zeiger darauf zurück und zeichnet die Tatsache auf, dass es nicht mehr kostenlos ist und wie groß es ist. Wenn Sie free () mit demselben Zeiger aufrufen, sucht free () nach der Größe dieses Chunks und fügt ihn wieder in die Liste der freien Chunks () ein. Wenn Sie malloc () aufrufen und kein ausreichend großer Block im Heap gefunden wird, wird der Heap mit dem Systemaufruf brk () vergrößert, dh die Adresse y erhöht und alle Adressen zwischen dem alten y und dem neuen y werden gültiger Speicher sein. brk () muss ein Systemaufruf sein;

malloc () ist system- / compilerabhängig, daher ist es schwierig, eine bestimmte Antwort zu geben. Grundsätzlich wird jedoch nachverfolgt, welcher Speicher zugewiesen ist, und je nachdem, wie dies geschieht, können Ihre Aufrufe zum Freigeben fehlschlagen oder erfolgreich sein.

malloc() and free() don't work the same way on every O/S.


1
Deshalb nennt man es undefiniertes Verhalten. Eine Implementierung könnte dazu führen, dass Dämonen aus Ihrer Nase fliegen, wenn Sie nach einem ungültigen Schreibvorgang kostenlos anrufen. Man weiß nie.
Braden Best

35

Eine Implementierung von malloc / free führt Folgendes aus:

  1. Holen Sie sich einen Speicherblock vom Betriebssystem über sbrk () (Unix-Aufruf).
  2. Erstellen Sie eine Kopf- und Fußzeile um diesen Speicherblock mit einigen Informationen wie Größe, Berechtigungen und dem nächsten und vorherigen Block.
  3. Wenn ein Aufruf von malloc eingeht, wird auf eine Liste verwiesen, die auf Blöcke der entsprechenden Größe verweist.
  4. Dieser Block wird dann zurückgegeben und Kopf- und Fußzeilen werden entsprechend aktualisiert.

25

Der Speicherschutz ist seitengranular und erfordert eine Kernel-Interaktion

Ihr Beispielcode fragt im Wesentlichen, warum das Beispielprogramm nicht abgefangen wird, und die Antwort lautet, dass der Speicherschutz eine Kernelfunktion ist und nur für ganze Seiten gilt, während der Speicherzuweiser eine Bibliotheksfunktion ist und .. ohne Durchsetzung .. willkürlich verwaltet große Blöcke, die oft viel kleiner als Seiten sind.

Speicher kann nur in Seiteneinheiten aus Ihrem Programm entfernt werden, und selbst das ist unwahrscheinlich.

calloc (3) und malloc (3) interagieren mit dem Kernel, um bei Bedarf Speicher zu erhalten. Die meisten Implementierungen von free (3) geben jedoch keinen Speicher an den Kernel 1 zurück , sondern fügen ihn einfach einer freien Liste hinzu, die calloc () und malloc () später abrufen, um die freigegebenen Blöcke wiederzuverwenden.

Selbst wenn ein free () Speicher an das System zurückgeben wollte, würde es mindestens eine zusammenhängende Speicherseite benötigen, damit der Kernel die Region tatsächlich schützt. Das Freigeben eines kleinen Blocks würde also nur dann zu einer Schutzänderung führen, wenn dies der Fall wäre der letzte kleine Block auf einer Seite.

Ihr Block ist also da und sitzt auf der freien Liste. Sie können fast immer darauf und auf den Speicher in der Nähe zugreifen, als wäre er noch zugewiesen. C kompiliert direkt zum Maschinencode und ohne spezielle Debugging-Vorkehrungen gibt es keine Überprüfung der Integrität von Ladungen und Speichern. Wenn Sie nun versuchen, auf einen freien Block zuzugreifen, ist das Verhalten vom Standard nicht definiert, um keine unangemessenen Anforderungen an Bibliotheksimplementierer zu stellen. Wenn Sie versuchen, auf freigegebenen Speicher oder Speicher außerhalb eines zugewiesenen Blocks zuzugreifen, können verschiedene Dinge schief gehen:

  • Manchmal verwalten Allokatoren separate Speicherblöcke, manchmal verwenden sie einen Header, den sie kurz vor oder nach Ihrem Block zuweisen (eine "Fußzeile", denke ich), aber sie möchten möglicherweise nur Speicher innerhalb des Blocks verwenden, um die freie Liste beizubehalten miteinander verbunden. Wenn ja, ist das Lesen des Blocks in Ordnung, aber sein Inhalt kann sich ändern, und das Schreiben in den Block kann dazu führen, dass sich der Allokator schlecht verhält oder abstürzt.
  • Natürlich kann Ihr Block in Zukunft zugewiesen werden, und dann wird er wahrscheinlich von Ihrem Code oder einer Bibliotheksroutine oder von calloc () mit Nullen überschrieben.
  • Wenn der Block neu zugewiesen wird, kann sich auch seine Größe ändern. In diesem Fall werden an verschiedenen Stellen noch weitere Links oder Initialisierungen geschrieben.
  • Offensichtlich können Sie so weit außerhalb des Bereichs verweisen, dass Sie eine Grenze eines der Kernel-bekannten Segmente Ihres Programms überschreiten, und in diesem Fall werden Sie eine Falle stellen.

Theorie der Arbeitsweise

Malloc (3) arbeitet also rückwärts von Ihrem Beispiel zur Gesamttheorie und erhält Speicher vom Kernel, wenn er benötigt wird, und normalerweise in Seiteneinheiten. Diese Seiten werden je nach Programm unterteilt oder konsolidiert. Malloc und Free arbeiten zusammen, um ein Verzeichnis zu führen. Sie verschmelzen nach Möglichkeit benachbarte freie Blöcke, um große Blöcke bereitstellen zu können. Das Verzeichnis kann die Verwendung des Speichers in freigegebenen Blöcken umfassen, um eine verknüpfte Liste zu bilden. (Die Alternative ist etwas gemeinsam genutzter Speicher und Paging-freundlicher und beinhaltet die Zuweisung von Speicher speziell für das Verzeichnis.) Malloc und Free können den Zugriff auf einzelne Blöcke kaum erzwingen, selbst wenn spezieller und optionaler Debugging-Code kompiliert wird das Programm.


1. Die Tatsache, dass nur sehr wenige Implementierungen von free () versuchen, Speicher an das System zurückzugeben, ist nicht unbedingt darauf zurückzuführen, dass die Implementierer nachlassen. Die Interaktion mit dem Kernel ist viel langsamer als die einfache Ausführung von Bibliothekscode, und der Nutzen wäre gering. Die meisten Programme haben einen stationären oder zunehmenden Speicherbedarf, sodass die Zeit, die für die Analyse des Heapspeichers auf der Suche nach Mehrwegspeicher aufgewendet wird, vollständig verschwendet wird. Andere Gründe sind die Tatsache, dass die interne Fragmentierung die Existenz von seitenausgerichteten Blöcken unwahrscheinlich macht und dass die Rückgabe eines Blocks wahrscheinlich Blöcke zu beiden Seiten fragmentieren würde. Schließlich umgehen die wenigen Programme, die viel Speicher zurückgeben, wahrscheinlich malloc () und weisen ohnehin einfach Seiten zu und geben sie frei.


Gute Antwort. Ich würde das Papier empfehlen: Dynamic Storage Allocation: Eine Umfrage und eine kritische Überprüfung von Wilson et al. Für eine eingehende Überprüfung der internen Mechanismen wie Headerfelder und freie Listen, die von Zuweisern verwendet werden.
Goaler444

23

Theoretisch erhält malloc für diese Anwendung Speicher vom Betriebssystem. Da Sie jedoch möglicherweise nur 4 Bytes benötigen und das Betriebssystem in Seiten (häufig 4 KB) arbeiten muss, leistet malloc etwas mehr. Es nimmt eine Seite auf und fügt dort seine eigenen Informationen ein, damit es verfolgen kann, was Sie dieser Seite zugewiesen und von ihr befreit haben.

Wenn Sie beispielsweise 4 Bytes zuweisen, gibt Ihnen malloc einen Zeiger auf 4 Bytes. Was Sie möglicherweise nicht erkennen, ist, dass der Speicher 8-12 Bytes vor Ihren 4 Bytes von malloc verwendet wird, um eine Kette des gesamten von Ihnen zugewiesenen Speichers zu erstellen. Wenn Sie kostenlos anrufen, nimmt es Ihren Zeiger, sichert sich dort, wo sich seine Daten befinden, und bearbeitet diesen.

Wenn Sie Speicher freigeben, nimmt malloc diesen Speicherblock aus der Kette ... und gibt diesen Speicher möglicherweise an das Betriebssystem zurück oder nicht. Wenn dies der Fall ist, schlägt der Zugriff auf diesen Speicher wahrscheinlich fehl, da das Betriebssystem Ihnen die Berechtigungen für den Zugriff auf diesen Speicherort entzieht. Wenn malloc den Speicher behält (weil auf dieser Seite andere Dinge zugewiesen sind oder für eine Optimierung), funktioniert der Zugriff zufällig. Es ist immer noch falsch, aber es könnte funktionieren.

HAFTUNGSAUSSCHLUSS: Was ich beschrieben habe, ist eine übliche Implementierung von Malloc, aber keineswegs die einzig mögliche.


12

Ihre strcpy-Zeile versucht aufgrund des NUL-Terminators, 9 Bytes und nicht 8 Bytes zu speichern. Es ruft undefiniertes Verhalten auf.

Der Aufruf zum kostenlosen kann abstürzen oder nicht. Der Speicher "nach" den 4 Bytes Ihrer Zuordnung wird möglicherweise von Ihrer C- oder C ++ - Implementierung für etwas anderes verwendet. Wenn es für etwas anderes verwendet wird, führt das Kritzeln dazu, dass "etwas anderes" schief geht. Wenn es jedoch nicht für etwas anderes verwendet wird, kann es passieren, dass Sie damit durchkommen. "Weg damit" klingt vielleicht gut, ist aber tatsächlich schlecht, da es bedeutet, dass Ihr Code in Ordnung zu sein scheint, aber bei einem zukünftigen Lauf werden Sie möglicherweise nicht damit durchkommen.

Bei einem Speicherzuweiser im Debugging-Stil stellen Sie möglicherweise fest, dass dort ein spezieller Schutzwert geschrieben wurde und dass dieser Wert kostenlos überprüft wird und in Panik gerät, wenn er nicht gefunden wird.

Andernfalls stellen Sie möglicherweise fest, dass die nächsten 5 Bytes einen Teil eines Verbindungsknotens enthalten, der zu einem anderen Speicherblock gehört, der noch nicht zugewiesen wurde. Das Freigeben Ihres Blocks kann durchaus das Hinzufügen zu einer Liste verfügbarer Blöcke umfassen. Da Sie in den Listenknoten gekritzelt haben, kann diese Operation einen Zeiger mit einem ungültigen Wert dereferenzieren und einen Absturz verursachen.

Es hängt alles vom Speicherzuweiser ab - unterschiedliche Implementierungen verwenden unterschiedliche Mechanismen.


12

Wie malloc () und free () funktionieren, hängt von der verwendeten Laufzeitbibliothek ab. Im Allgemeinen weist malloc () dem Betriebssystem einen Heap (einen Speicherblock) zu. Jede Anforderung an malloc () weist dann einen kleinen Teil dieses Speichers zu und gibt einen Zeiger an den Aufrufer zurück. Die Speicherzuweisungsroutinen müssen einige zusätzliche Informationen über den zugewiesenen Speicherblock speichern, um den verwendeten und freien Speicher auf dem Heap verfolgen zu können. Diese Informationen werden häufig in wenigen Bytes unmittelbar vor dem von malloc () zurückgegebenen Zeiger gespeichert und können eine verknüpfte Liste von Speicherblöcken sein.

Wenn Sie über den von malloc () zugewiesenen Speicherblock hinaus schreiben, werden Sie höchstwahrscheinlich einige der Buchhaltungsinformationen des nächsten Blocks zerstören, der möglicherweise der verbleibende nicht verwendete Speicherblock ist.

Ein Ort, an dem Ihr Programm möglicherweise ebenfalls abstürzt, ist das Kopieren zu vieler Zeichen in den Puffer. Wenn sich die zusätzlichen Zeichen außerhalb des Heaps befinden, kann es zu einer Zugriffsverletzung kommen, wenn Sie versuchen, in nicht vorhandenen Speicher zu schreiben.


6

Dies hat nichts spezielles mit malloc und free zu tun. Ihr Programm zeigt nach dem Kopieren der Zeichenfolge ein undefiniertes Verhalten - es kann zu diesem Zeitpunkt oder zu einem beliebigen späteren Zeitpunkt abstürzen. Dies gilt auch dann, wenn Sie nie malloc und free verwendet und das char-Array auf dem Stapel oder statisch zugewiesen haben.


5

malloc und free sind implementierungsabhängig. Eine typische Implementierung besteht darin, den verfügbaren Speicher in eine "freie Liste" zu partitionieren - eine verknüpfte Liste der verfügbaren Speicherblöcke. Viele Implementierungen unterteilen es künstlich in kleine und große Objekte. Freie Blöcke beginnen mit Informationen darüber, wie groß der Speicherblock ist und wo der nächste ist usw.

Wenn Sie malloc, wird ein Block von der freien Liste gezogen. Wenn Sie freigeben, wird der Block wieder in die kostenlose Liste aufgenommen. Wenn Sie das Ende Ihres Zeigers überschreiben, schreiben Sie wahrscheinlich in die Kopfzeile eines Blocks in der freien Liste. Wenn Sie Ihren Speicher freigeben, versucht free (), auf den nächsten Block zu schauen, und trifft wahrscheinlich auf einen Zeiger, der einen Busfehler verursacht.


4

Nun, es hängt von der Implementierung des Speicherzuweisers und dem Betriebssystem ab.

Unter Windows kann ein Prozess beispielsweise eine Seite oder mehr RAM anfordern. Das Betriebssystem weist diese Seiten dann dem Prozess zu. Dies ist jedoch nicht der Ihrer Anwendung zugewiesene Speicher. Der CRT-Speicherzuweiser markiert den Speicher als zusammenhängenden "verfügbaren" Block. Der CRT-Speicherzuweiser durchläuft dann die Liste der freien Blöcke und findet den kleinstmöglichen Block, den er verwenden kann. Es nimmt dann so viel von diesem Block, wie es benötigt, und fügt ihn einer "zugewiesenen" Liste hinzu. Am Kopf der eigentlichen Speicherzuordnung ist ein Header angebracht. Dieser Header enthält verschiedene Informationen (er kann beispielsweise die nächsten und vorherigen zugewiesenen Blöcke enthalten, um eine verknüpfte Liste zu bilden. Er enthält höchstwahrscheinlich die Größe der Zuordnung).

Free entfernt dann den Header und fügt ihn wieder der Liste des freien Speichers hinzu. Wenn es mit den umgebenden freien Blöcken einen größeren Block bildet, werden diese zu einem größeren Block addiert. Wenn jetzt eine ganze Seite frei ist, gibt der Allokator die Seite höchstwahrscheinlich an das Betriebssystem zurück.

Es ist kein einfaches Problem. Der OS-Allokator-Teil liegt völlig außerhalb Ihrer Kontrolle. Ich empfehle Ihnen, etwas wie Doug Leas Malloc (DLMalloc) durchzulesen, um zu verstehen, wie ein ziemlich schneller Allokator funktioniert.

Bearbeiten: Ihr Absturz wird durch die Tatsache verursacht, dass Sie durch Schreiben, das größer als die Zuordnung ist, den nächsten Speicherheader überschrieben haben. Auf diese Weise wird es beim Freigeben sehr verwirrt, was genau es freigibt und wie es in den folgenden Block übergeht. Dies kann nicht immer sofort zu einem Absturz führen. Dies kann später zu einem Absturz führen. Vermeiden Sie generell Speicherüberschreibungen!


3

Ihr Programm stürzt ab, weil es Speicher verwendet, der Ihnen nicht gehört. Es kann von jemand anderem verwendet werden oder nicht - wenn Sie Glück haben, stürzen Sie ab, wenn nicht, bleibt das Problem möglicherweise lange verborgen und kommt zurück und beißt Sie später.

Was die malloc / freie Implementierung angeht, sind ganze Bücher dem Thema gewidmet. Grundsätzlich würde der Allokator größere Speicherblöcke vom Betriebssystem erhalten und diese für Sie verwalten. Einige der Probleme, die ein Allokator angehen muss, sind:

  • So erhalten Sie neuen Speicher
  • So speichern Sie es - (Liste oder andere Struktur, mehrere Listen für Speicherblöcke unterschiedlicher Größe usw.)
  • Was tun, wenn der Benutzer mehr Speicher als derzeit verfügbar anfordert (mehr Speicher vom Betriebssystem anfordern, einige der vorhandenen Blöcke verbinden, wie sie genau verbunden werden, ...)
  • Was tun, wenn der Benutzer Speicher freigibt?
  • Debug-Allokatoren geben Ihnen möglicherweise einen größeren Teil, den Sie angefordert haben, und füllen ihn mit einem Byte-Muster. Wenn Sie den Speicher freigeben, kann der Allokator prüfen, ob er außerhalb des Blocks geschrieben wurde (was in Ihrem Fall wahrscheinlich passiert) ...

2

Es ist schwer zu sagen, da das tatsächliche Verhalten zwischen verschiedenen Compilern / Laufzeiten unterschiedlich ist. Sogar Debug- / Release-Builds verhalten sich anders. Debug-Builds von VS2005 fügen Markierungen zwischen Zuweisungen ein, um eine Speicherbeschädigung zu erkennen. Anstelle eines Absturzes wird dies in free () bestätigt.


1

Es ist auch wichtig zu wissen, dass durch einfaches Bewegen des Programmunterbrechungszeigers mit brkund sbrkohne Zuweisen des Speichers nur der Adressraum eingerichtet wird. Unter Linux wird der Speicher beispielsweise durch tatsächliche physische Seiten "gesichert", wenn auf diesen Adressbereich zugegriffen wird, was zu einem Seitenfehler führt und schließlich dazu führt, dass der Kernel den Seitenzuweiser aufruft, um eine Sicherungsseite zu erhalten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.