2014-04-11 11 views
21

W systemie 64-bitowym liczba całkowita w Pythonie zajmuje 24 bajty. Jest to 3-krotność pamięci, która byłaby potrzebna w np. C dla 64-bitowej liczby całkowitej. Teraz wiem, że to dlatego, że liczby w języku Python są obiektami. Ale do czego służy dodatkowa pamięć? Mam swoje domysły, ale byłoby miło wiedzieć na pewno.Dlaczego ints wymagają trzy razy więcej pamięci w Pythonie?

+2

Zobacz ten artykuł: http://www.laurentluce.com/posts/python-integer-objects-implementation/ a także https://docs.python.org/2/c-api/structures.html do wspólnego struktury obiektowe w Pythonie – DNA

+0

@DNA: mówi o podstawowym typie 'int' Pythona 2; typ 'long' w Pythonie 2 (zastępujący typ' int' w Pythonie 3) jest nieco bardziej skomplikowany. –

+0

Należy zauważyć, że to pytanie i odpowiedzi są specyficzne dla implementacji referencyjnej CPython. Inne implementacje mogą mieć całkowicie inne zastosowanie pamięci (chociaż obowiązują te same ogólne zasady: rozmiar i inne metadane obiektu muszą być przechowywane). – Bob

Odpowiedz

30

Należy pamiętać, że typ Python int nie ma ograniczonego zakresu, na przykład C int; jedynym ograniczeniem jest dostępna pamięć.

Pamięć przechodzi do przechowywania wartości, bieżącego rozmiaru pamięci całkowitej (rozmiar pamięci jest zmienny, aby obsługiwać dowolne rozmiary), oraz standardowego przechowywania obiektów w języku Python (odniesienie do odpowiedniego obiektu i licznika odwołań).

Można wyszukać longintrepr.h source (typ Python 3 int był tradycyjnie znany jako typ long w Pythonie 2); to sprawia, że ​​efektywne wykorzystanie PyVarObject C type śledzić całkowitą wielkość:

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

sklepach ob_digit array „” z cyfr albo 15 lub 30 bitów szerokości (w zależności od platformy); tak na moim 64-bitowym systemie OS X, liczba całkowita do (2^30) - 1 używa 1 'cyfra':

>>> sys.getsizeof((1 << 30) - 1) 
28 

ale jeśli używasz 2 30-bitowych cyfr w liczbie dodatkowe 4 bajty są potrzebne, itp:

>>> sys.getsizeof(1 << 30) 
32 
>>> sys.getsizeof(1 << 60) 
36 
>>> sys.getsizeof(1 << 90) 
40 

podstawa 24 bajty są więc struktura PyObject_VAR_HEAD, posiadających rozmiar obiektu, liczba odniesienia i wskaźnik typu (po 8 bajtów/64 bitów na moim 64-bitowe OS X platform) .

W Pythonie 2, całkowitymi < = sys.maxint ale> = -sys.maxint - 1 są przechowywane przy użyciu simpler structure przechowującą tylko jedną wartość:

typedef struct { 
    PyObject_HEAD 
    long ob_ival; 
} PyIntObject; 

ponieważ wykorzystuje PyObject zamiast PyVarObject nie ma ob_size pola w struktury i rozmiar pamięci jest ograniczony do 24 bajtów; 8 dla wartości long, 8 dla licznika referencji i 8 dla wskaźnika obiektu typu.

+0

W jaki sposób obsługiwane są wartości ujemne, jeśli int jest podane jako ciąg cyfr? Czy istnieje koncepcja dodatku dwóch w python? Jeśli wydrukuję szesnastkowo (-1) otrzymam -0x1 lub podobnie, jeśli wydrukuję bin (-1) otrzymam -0b1 Rozumiem, że to nie może być to, co jest reprezentowane wewnętrznie, jednak w jaki sposób python podejmuje decyzję, że jest to wartość ujemna czy wysoki bit nie jest ustawiony? – Har

+1

@Har: rozmiar obiektu jest ustawiony na wartość ujemną. patrz [połączony plik nagłówka] (https://hg.python.org/cpython/file/5e303360db14/Include/longintrepr.h#l74) * Liczby ujemne są reprezentowane ob_size <0; *. Więc reprezentacja całkowita, która wymaga 2 wpisów 'ob_digits', wtedy' ob_size' ma wartość '2' lub' -2', druga sygnalizuje, że jest liczbą całkowitą ujemną. –

+0

oznacza to, że nie jest to dwójkowe uzupełnienie, ale po prostu jest trochę w strukturze, co oznacza, czy jest ujemny czy nie? – Har

1

Z longintrepr.h widzimy, że 'int' Przedmiot pytona jest określona w tej konstrukcji C:

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

cyfra jest 32-bitową wartością bez znaku. Większość miejsca zajmuje nagłówek obiektu o zmiennym rozmiarze. Od object.h, możemy znaleźć jego definicję:

typedef struct { 
    PyObject ob_base; 
    Py_ssize_t ob_size; /* Number of items in variable part */ 
} PyVarObject; 

typedef struct _object { 
    _PyObject_HEAD_EXTRA 
    Py_ssize_t ob_refcnt; 
    struct _typeobject *ob_type; 
} PyObject; 

Widzimy, że używamy Py_ssize_t, 64-bity zakładając systemu 64-bitowego do przechowywania rachubę „cyfry” w wartości. Jest to prawdopodobnie marnotrawstwo. Możemy również zobaczyć, że ogólny nagłówek obiektu ma 64-bitową liczbę odwołań oraz wskaźnik do typu obiektu, który również będzie 64-bitowym magazynem. Licznik odwołań jest konieczny, aby Python wiedział, kiedy zwolnić obiekt, a wskaźnik do typu obiektu jest konieczny, aby wiedzieć, że mamy int, a nie, powiedzmy, łańcuch, ponieważ struktury C nie mają możliwości przetestowania typu obiekt z dowolnego wskaźnika.

_PyObject_HEAD_EXTRA nie jest zdefiniowany w większości kompilacji Pythona, ale może być używany do przechowywania połączonej listy wszystkich obiektów Pythona na stercie, jeśli kompozycja włącza tę opcję, używając kolejnych dwóch wskaźników po 64 bity.