Python-Speicher und Zahlen

Hallo zusammen.

Früher habe ich mit C-ähnlichen Sprachen gearbeitet, jetzt musste ich mich mit Python zusammensetzen. Die Syntax war einfach und es waren schwierige Fragen. Under cat - ein Artikel darüber, wie Python die Datenspeicherung im Speicher implementiert. Ich gebe nicht vor, wahr zu sein, aber versuche es herauszufinden.

Wir schauen uns die Links an


Beginnen wir mit dem Einfachsten. Alle Daten in Python sind ein Objekt, jede Variable ist eine Referenz auf ein Objekt. Es gibt keine Daten, die kein Objekt sind. Zunächst müssen wir lernen, zu bestimmen, ob zwei "identische" Objekte ein und dasselbe sind. Dazu müssen Sie die Adresse abrufen, mit der Sie die integrierte Funktion id () problemlos ausführen können. Wir versuchen:

print(id(0))

Wie erwartet wird etwas Unverständliches ausgegeben. Eine große Anzahl ist wahrscheinlich wirklich eine Adresse. Wenn jedoch jede durchgehend verwendete Nummer im Speicher abgelegt ist, reicht natürlich kein Speicher aus. Ein kurzes Experiment wird durchgeführt:

print(id(0))
print(id(0))

Zwei absolut identische Zahlen. Daher werden alle konstanten Zahlen tatsächlich ohne Duplizierung gespeichert. Es ist logisch - Python hat bereits eine geringe Produktivität. Mit einem solchen Trick können Sie die letzten Überreste speichern. Okay, lassen Sie uns versuchen, den gesamten Speicher mit einer großen Anzahl von Nullen zu füllen.

a = [0]
while True:
    a += [0]

Der Endloszyklus läuft erwartungsgemäß endlos, benötigt jedoch praktisch keinen Speicher. Ein weiteres Experiment:

a = [0, 0]
print(id(a[0]))
print(id(a[1]))

Na ja, die gleiche Nummer. Um zu bestätigen, führe ich dieselbe Prüfung mit zwei verschiedenen Variablen durch - der gleichen Nummer und sogar gleich id (0). Das heißt, der Algorithmus sieht anscheinend so aus: Wenn sich der Variablenwert ändert, prüfen wir, ob er im Speicher identisch ist, und leiten in diesem Fall die Verknüpfung zu ihm um. Dieses Verhalten ist offensichtlich erforderlich, da ein Objekt viel Speicherplatz in Anspruch nimmt. Um kompakter zu sein, nutzt Python die vorhandenen Objekte optimal aus. Um den Artikel nicht mit Code zu überfrachten, sage ich, dass dies für Zeichenfolgen (einschließlich der durch ein Slice erhaltenen), logische Objekte und sogar Arrays genauso funktioniert. Machen wir einen zweiten Versuch, um den gesamten Speicher in Python zu nutzen:

i = 0
a = [0]
while True:
    a += [a[i]]
    i += 1

Erfolg! Der Speicherverbrauch steigt ständig. Wir ziehen die erste Schlussfolgerung:
1. Alle Daten in Python sind ein Objekt.
2. Wenn die Objekte „gleich“ sind, werden sie an derselben Adresse im Speicher abgelegt. Mit anderen Worten, a == b und id (a) == id (b) sind äquivalente Anweisungen.
3. Es wird keine kompliziertere Optimierung verwendet - eine relativ einfache Abhängigkeit im Array wird in keiner Weise mehr optimiert (nur die Regel "a [i] = i"). Es würde mich jedoch wundern, wenn ich es verwenden würde: Hier ist eine ziemlich komplizierte lexikalische Analyse erforderlich, die sich Python mit seiner schrittweisen Interpretation nicht leisten kann.

Links zählen


Haftungsausschluss: Wir werden jetzt im interaktiven Python-Modus arbeiten. Um Verweise auf ein Objekt zu zählen, gibt es eine Funktion sys.getrefcount (). System importieren:

>>> from os import sys

Und für den Anfang müssen wir feststellen, wie real die Daten sind, die sie produzieren:

>>> sys.getrefcount('There is no this string in Python')
3
>>> sys.getrefcount('9695c3716e3b801367b7eca6a3281ac9') #md5-хеш 512 рандомных байт из /dev/urandom.
3
>>> a = 'More random for the random god!'
>>> sys.getrefcount(a)
2
>>> a = 0
>>> sys.getrefcount(a)
434
>>> sys.getrefcount(0)
436

Dies sagt uns eine lustige Sache: Links zählen, getrefcount () erstellt sie selbst. Wie wir sehen können, erstellt er für Konstanten zwei von ihnen (tatsächlich zwei, ich habe große Mengen an Eingabedaten verwendet, die ich hier nicht als unnötig veröffentliche), sodass wir nur 2 subtrahieren können. Tatsächlich erstellt er anscheinend für die Variablen auch zwei , berücksichtigt aber nicht die Variable selbst. Nun, wir haben die Abweichungen der Ergebnisse von der Realität herausgefunden. Nun ein paar Beispiele:

>>> sys.getrefcount(1)
754
>>> sys.getrefcount(65)
13
>>> sys.getrefcount(67)
11
>>> sys.getrefcount('A')
4
>>> sys.getrefcount('a')
6
>>> sys.getrefcount(False)
100
>>> sys.getrefcount(True)
101
# Истина победила!

Warum erscheinen Zeiger plötzlich aus heiterem Himmel (eine ganze Zahl von 751 Stück pro Einheit)? Da diese Funktion C-Zeiger zählt, enthält sie auch diejenigen, die im Python-Code selbst verwendet werden. Tatsächlich brechen wir unverschämt in den Teil von Python ein, den Entwickler vor uns verstecken wollen.

Hier ist so eine Kulisse in Python. Wenn meine Hände reichen und ich schreiben kann, was passieren wird, wenn Sie versuchen, diese Objekte manuell über OllyDbg zu ändern, sagen wir.

Jetzt auch beliebt: