In Python 2.6.2 ist ein "int" so definiert:
Code: Alles auswählen
typedef struct {
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
long ob_ival;
} PyIntObject;
Das sind mindestens 16 Bytes bei 32-Bit-Compilern und 24 bei 64-Bit-Compilern. Kleine Zahlen um 0 herum sind vorinitialisiert und werden wiederverwendet. Der Rest wird jedes Mal angelegt.
Der klassische, wenn auch nicht ANSI-C-Standardkonforme Weg wäre, kleine Datentypen wie "int", "bool" oder "char" als "tagged immediate values" wie Pointer zu verwalten. Das wäre effizienter. Dafür hat dann ein "int" auch nur 30 oder 31 Bits. Entweder nutzt man als, dass Zeiger immer auf Vielfache von 4 oder 8 zeigen und somit ihre untersten 2 oder 3 Bits immer 0 sind und man daher Zahlen, dadurch markieren kann, dass ihr unterstes Bit immer gesetzt ist oder man dreht die Kodierung um und markiert Zeiger durch ein gesetztes Bit und sorgt dafür, das Integer immer eine 0 im untersten Bit haben. Je nach Prozessor ist mal das eine und mal das andere Verfahren besser. Auf einer SPARC-Architektur markiert man IIRC besser Zeiger, weil es egal ist, was da steht, denn das wird vom Prozessor ignoriert. Ein 68000er wiederum reagiert allergisch, wenn die Adressregister eine ungerade Adresse enthalten und da ist war es besser, Zahlen zu markieren. Wie das auf den heute allgegenwärtigen Intel-Maschinen ist, weiß ich nicht.
In einem 64-Bit-System könnte man aber damit experimentieren, das oberste Byte als Tag zu benutzen. So große Adressräume gibt es eh nicht und Zahlen könnten dann immer noch 56-Bit haben, bevor man auf eine andere Darstellung wechseln muss. Vielleicht könnte man sogar direkt einen Index auf die Klasse als Tag ablegen, für den man sich dann 16 Bits genehmigt.
Fazit: Die Speicherverwaltung von CPython ist ineffizient und verschwenderisch. Und Referenzen zu zählen macht das System langsamer als hätte man nur einen modernen (d.h. Stand von 1986) Garbage Collector.
Doch ich schweife ab...
Stefan