2014-04-11 13 views
21

Trên hệ thống 64 bit, một số nguyên trong Python mất 24 byte. Điều này gấp 3 lần bộ nhớ cần thiết, ví dụ: C cho số nguyên 64 bit. Bây giờ, tôi biết điều này là bởi vì các số nguyên Python là các đối tượng. Nhưng bộ nhớ phụ được sử dụng để làm gì? Tôi có dự đoán của tôi, nhưng nó sẽ được tốt đẹp để biết chắc chắn.Tại sao int yêu cầu bộ nhớ gấp ba lần trong Python?

+2

Xem bài viết này: http://www.laurentluce.com/posts/python-integer-objects-implementation/ và cũng https://docs.python.org/2/c-api/structures.html cho chung các cấu trúc đối tượng trong Python – DNA

+0

@DNA: nói về kiểu cơ bản của Python 2 int '; loại 'long' trong Python 2 (thay thế kiểu' int' trong Python 3) vẫn còn phức tạp hơn một chút. –

+0

Lưu ý rằng câu hỏi này và câu trả lời của nó là cụ thể cho việc triển khai tham chiếu CPython. Các triển khai khác có thể có sử dụng bộ nhớ hoàn toàn khác nhau (mặc dù, các nguyên tắc chung tương tự áp dụng: kích thước và siêu dữ liệu đối tượng khác cần được lưu trữ). – Bob

Trả lời

30

Hãy nhớ rằng loại Python int không có phạm vi giới hạn như C int có; giới hạn duy nhất là bộ nhớ có sẵn.

Bộ nhớ lưu trữ giá trị, kích thước lưu trữ số nguyên hiện tại (kích thước lưu trữ là biến để hỗ trợ kích thước tùy ý) và sổ sách kế toán đối tượng Python chuẩn (tham chiếu đến đối tượng liên quan và số tham chiếu).

Bạn có thể tra cứu longintrepr.h source (loại Python 3 int được gọi theo kiểu truyền thống là loại long trong Python 2); nó làm cho sử dụng hiệu quả các PyVarObject C type để theo dõi kích thước nguyên:

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

Các cửa hàng ob_digit mảng 'chữ số' của 15 hoặc 30 bit rộng (tùy thuộc vào nền tảng của bạn); vân vân hệ thống của tôi 64-bit OS X, một số nguyên lên đến (2^30) - 1 sử dụng 1 'chữ số':

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

nhưng nếu bạn sử dụng 2 chữ số 30-bit trong số thêm 4 byte là cần thiết, vv:

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

các cơ sở 24 byte sau đó là những cấu trúc PyObject_VAR_HEAD, giữ kích thước đối tượng, số lượng tài liệu tham khảo và các con trỏ kiểu (mỗi 8 byte/64 bit trên nền tảng của tôi 64-bit OS X) .

Mở Python 2, số nguyên < = sys.maxint nhưng> = -sys.maxint - 1 được lưu trữ bằng cách sử dụng chỉ là giá trị duy nhất simpler structure lưu trữ:

typedef struct { 
    PyObject_HEAD 
    long ob_ival; 
} PyIntObject; 

vì này sử dụng PyObject thay vì PyVarObject không có ob_size trường trong struct và kích thước bộ nhớ bị giới hạn chỉ 24 byte; 8 cho giá trị long, 8 cho số tham chiếu và 8 cho con trỏ đối tượng kiểu.

+0

Giá trị âm được xử lý như thế nào, nếu một int được đưa ra dưới dạng một chuỗi các chữ số? Có một khái niệm về bổ sung twos trong python? Nếu tôi in hex (-1) tôi nhận được -0x1 hoặc tương tự nếu tôi in bin (-1) tôi nhận được -0b1 tôi hiểu rằng điều này có thể không được đại diện nội bộ, tuy nhiên làm thế nào để python đưa ra quyết định rằng nó là giá trị âm nếu bit cao không được thiết lập? – Har

+1

@Har: kích thước đối tượng được đặt thành giá trị âm. xem [tệp tiêu đề được liên kết] (https://hg.python.org/cpython/file/5e303360db14/Include/longintrepr.h#l74): * Các số âm được biểu diễn bằng ob_size <0; *. Vì vậy, một biểu diễn số nguyên yêu cầu 2 mục 'ob_digits', sau đó' ob_size' là '2' hoặc' -2', tín hiệu thứ hai là số nguyên âm. –

+0

để điều đó có nghĩa rằng nó không phải là một bổ sung twos nó chỉ đơn giản là một chút trong cấu trúc đại diện cho dù đó là tiêu cực hay không? – Har

1

Từ longintrepr.h, chúng ta thấy rằng một Python 'int' đối tượng được định nghĩa với cấu trúc C này:

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

Digit là một giá trị unsigned 32-bit. Phần lớn không gian được lấy bởi tiêu đề đối tượng có kích thước biến. Từ object.h, chúng ta có thể tìm thấy định nghĩa của nó:

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; 

Chúng ta có thể thấy rằng chúng tôi đang sử dụng một Py_ssize_t, 64-bit giả sử hệ thống 64-bit, để lưu trữ các tội danh "chữ số" trong giá trị. Điều này có thể lãng phí. Chúng ta cũng có thể thấy rằng tiêu đề đối tượng chung có số tham chiếu 64 bit và một con trỏ đến kiểu đối tượng, cũng sẽ là một lưu trữ 64 bit. Số tham chiếu là cần thiết để Python biết khi nào cần xử lý đối tượng, và con trỏ đến kiểu đối tượng là cần thiết để biết rằng chúng ta có một int và không, một chuỗi, vì cấu trúc C không có cách nào để kiểm tra kiểu một đối tượng từ một con trỏ tùy ý.

_PyObject_HEAD_EXTRA được định nghĩa là không có gì trên hầu hết các bản dựng python, nhưng có thể được sử dụng để lưu trữ danh sách được liên kết của tất cả các đối tượng Python trên heap nếu xây dựng cho phép tùy chọn đó sử dụng hai con trỏ khác 64 bit.

Các vấn đề liên quan