Comprendre l'allocation de mémoire pour les grands entiers en Python

comment Python affecte-t-il la mémoire pour les grands nombres entiers?

un type int a une taille de 28 bytes et comme je continue à augmenter la valeur du int , la taille augmente par incréments de 4 bytes .

  1. pourquoi 28 bytes initialement pour toute valeur aussi basse que 1 ?

  2. pourquoi des incréments de 4 bytes ?

PS: J'exécute Python 3.5.2 sur une machine x86_64 (64 bits). Tous les indicateurs/ressources / PEPs sur la façon dont les interprètes (3.0+) travaillent sur de tels nombres énormes est ce que je cherche.

Code illustrant les dimensions:

>>> a=1
>>> print(a.__sizeof__())
28
>>> a=1024
>>> print(a.__sizeof__())
28
>>> a=1024*1024*1024
>>> print(a.__sizeof__())
32
>>> a=1024*1024*1024*1024
>>> print(a.__sizeof__())
32
>>> a=1024*1024*1024*1024*1024*1024
>>> a
1152921504606846976
>>> print(a.__sizeof__())
36
29
demandé sur Jim Fasarakis Hilliard 2016-10-31 17:25:36

2 réponses

pourquoi 28 octets initialement pour une valeur aussi basse que 1 ?

je crois @bgusach a répondu que complètement; Python utilise C structures pour représenter des objets dans le monde de Python, tous les objets y compris int s :

struct _longobject {
    PyObject_VAR_HEAD
    digit ob_digit[1];
};

PyObject_VAR_HEAD est une macro qui, lorsqu'elle est étendue, ajoute un autre champ dans la structure (champ PyVarObject qui est spécifiquement utilisé pour les objets qui ont une certaine notion de longueur) et, ob_digits est un tableau contenant la valeur du nombre. La chaudière-plaque dans la taille vient de cette structure, pour les petits et grands nombres de Python.

pourquoi incréments de 4 octets?

parce que, quand un plus grand nombre est créé, la taille (en octets) est un multiple du sizeof(digit) ; vous pouvez voir que dans _PyLong_New où l'attribution de la mémoire pour un nouveau longobject est effectuée avec PyObject_MALLOC :

/* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +
   sizeof(digit)*size.  Previous incarnations of this code used
   sizeof(PyVarObject) instead of the offsetof, but this risks being
   incorrect in the presence of padding between the PyVarObject header
   and the digits. */
if (size > (Py_ssize_t)MAX_LONG_DIGITS) {
    PyErr_SetString(PyExc_OverflowError,
                    "too many digits in integer");
    return NULL;
}
result = PyObject_MALLOC(offsetof(PyLongObject, ob_digit) +
                         size*sizeof(digit));

offsetof(PyLongObject, ob_digit) est la "plaque chauffante" (en octets) pour le long objet qui n'est pas lié à la conservation de sa valeur.

digit est défini dans le fichier d'en-tête struct _longobject comme typedef pour uint32 :

typedef uint32_t digit;

et sizeof(uint32_t) est 4 octets. C'est le montant par lequel vous verrez la taille en octets augmenter lorsque l'argument size augmente à _PyLong_New .


bien sûr, C'est comme ça que C Python a choisi de l'implémenter. C'est un détail d'implémentation et en tant que tel vous ne trouverez pas beaucoup d'informations dans les Pep. Le la liste de diffusion python-dev tiendra des discussions sur l'implémentation si vous pouvez trouver le thread correspondant :-).

de toute façon, vous pourriez trouver des comportements différents dans d'autres implémentations populaires, alors ne le prenez pas pour acquis.

22
répondu Jim Fasarakis Hilliard 2017-05-23 12:25:13

c'est facile. Le int de Python n'est pas le genre de primitif auquel on peut être habitué à partir d'autres langues, mais un objet à part entière, avec ses méthodes et tout le reste. C'est là que la surcharge.

alors, vous avez la charge elle-même, l'entier qui est représenté. Et il n'y a pas de limite à cela, sauf votre mémoire.

la taille d'un Python int est ce dont il a besoin pour représenter le nombre plus un peu de surcharge.

si vous souhaitez lire la suite, consultez la partie de la documentation :

les entiers ont une précision illimitée

16
répondu bgusach 2016-10-31 19:19:21