Hướng dẫn how much memory is allocated to an empty list in python? - bao nhiêu bộ nhớ được cấp cho một danh sách trống trong python?

Trong Cpython, các yếu tố của một danh sách được lưu trữ dưới dạng con trỏ cho các yếu tố hơn là các giá trị của chính các yếu tố. Điều này thể hiện rõ từ cấu trúc đại diện cho một danh sách trong C:

// Fetched from CPython main branch. Removed comments for brevity.
typedef struct {

    PyObject_VAR_HEAD
    PyObject **ob_item; /* Pointer reference to the element. */
    Py_ssize_t allocated;

}PyListObject;

Một danh sách trống xây dựng PyObject và chiếm một số bộ nhớ:

from sys import getsizeof

l = []

print(getsizeof(l))

Điều này trả về:

Kích thước chính xác của một danh sách trống có thể thay đổi trên các phiên bản và triển khai Python khác nhau.

Một con trỏ duy nhất đến một phần tử yêu cầu 8 byte không gian trong danh sách. Bất cứ khi nào các yếu tố bổ sung được thêm vào danh sách, Python tự động phân bổ bộ nhớ thêm để phù hợp với các yếu tố trong tương lai mà không cần thay đổi kích thước container. Điều này ngụ ý, việc thêm một phần tử duy nhất vào một danh sách trống sẽ kích động Python để phân bổ nhiều bộ nhớ hơn 8 byte.

Hãy đặt điều này để kiểm tra và nối một số yếu tố vào danh sách:

# src.py
from sys import getsizeof

l = []
l.append(0)

print(getsizeof(l))

Điều này trả về:

Kích thước chính xác của một danh sách trống có thể thay đổi trên các phiên bản và triển khai Python khác nhau.

# src.py
from sys import getsizeof

l = []
l.append(0)
l.append(1)
l.append(2)
l.append(3)

print(getsizeof(l))

Một con trỏ duy nhất đến một phần tử yêu cầu 8 byte không gian trong danh sách. Bất cứ khi nào các yếu tố bổ sung được thêm vào danh sách, Python tự động phân bổ bộ nhớ thêm để phù hợp với các yếu tố trong tương lai mà không cần thay đổi kích thước container. Điều này ngụ ý, việc thêm một phần tử duy nhất vào một danh sách trống sẽ kích động Python để phân bổ nhiều bộ nhớ hơn 8 byte.

Hãy đặt điều này để kiểm tra và nối một số yếu tố vào danh sách:

# src.py
from sys import getsizeof

l = []
for i in range(6):
    l.append(l)

print(getsizeof(l))

# src.py
from sys import getsizeof

l = []
l.append(0)

print(getsizeof(l))

Đợi đã, kích thước của

from sys import getsizeof

l = []

print(getsizeof(l))
0 nên là 64 byte (56+8) nhưng thay vào đó, nó tăng lên 88 byte. Điều này xảy ra bởi vì trong trường hợp này, Python đã phân bổ quá mức 32 byte để phù hợp với các yếu tố đến trong tương lai. Bây giờ, nếu bạn nối thêm 3 yếu tố vào danh sách, bạn sẽ thấy rằng nó không tăng kích thước vì không có sự phân bổ lại đang xảy ra ở đây:

Bản in này:

Thêm một phần tử thứ năm vào danh sách trên sẽ tăng kích thước của danh sách lên 32 byte (có thể khác nhau trong các triển khai khác) một lần nữa:

Phân bổ bộ nhớ động này làm cho danh sách rất linh hoạt và vì một danh sách chỉ giữ các tham chiếu đến các yếu tố, nên nó có thể chứa các đối tượng không đồng nhất mà không có bất kỳ vấn đề nào. Nhưng tính linh hoạt này của việc có thể nối thêm bất kỳ số lượng yếu tố nào mà không bao giờ quan tâm đến việc phân bổ bộ nhớ, các kết quả với chi phí thời gian thực hiện chậm hơn.

In [1]: %%timeit
    ...:
    ...: l=[]
    ...: for i in range(10_000):
    ...:     l.append(i)
    ...:
499 µs ± 1.23 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

Mặc dù thông thường, bạn không cần phải suy nghĩ về việc tối ưu hóa điều này, có một cách cho phép bạn thực hiện phân bổ bộ nhớ trước trong danh sách thay vì để Python thực hiện phân bổ động cho bạn. Bằng cách này, bạn có thể đảm bảo rằng Python sẽ không phải thực hiện phân bổ bộ nhớ động nhiều lần khi danh sách của bạn phát triển.

# src.py
size = 10_000
l = [None] * size

for i in range(size):
    l[i] = i

Sự phân bổ trước tĩnh sẽ làm cho mã của bạn đi nhanh hơn một chút. Tôi đã phải làm điều này một lần trong một vòng lặp được lồng chặt và cải thiện hiệu suất 10% có ý nghĩa đối với dịch vụ mà tôi đang làm việc.

In [2]: %%timeit
    ...:
    ...: l=[None]*10_000
    ...: for i in range(10_000):
    ...:     l[i] = i
    ...:
321 µs ± 71.1 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

Bộ nhớ phân bổ trước trong danh sách

In [3]: %%timeit
    ...:
    ...: [i for i in range(10_000)]
225 µs ± 711 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)

Hãy đo lường hiệu suất của các yếu tố nối vào một danh sách trống. Tôi đang sử dụng lệnh

from sys import getsizeof

l = []

print(getsizeof(l))
1 tích hợp của Ipython để thực hiện:

Bây giờ, nếu bạn biết kích thước cuối cùng của danh sách trước đó, thì bạn không cần phải tạo một danh sách trống và nối các phần tử vào nó thông qua một vòng lặp. Bạn có thể khởi tạo danh sách với from sys import getsizeof l = [] print(getsizeof(l)) 2 và sau đó điền vào các yếu tố như sau:

  • Điều này khá nhanh hơn một chút so với đoạn trích trước đó:

Bao nhiêu bộ nhớ được phân bổ cho một danh sách trong Python?

Bất cứ khi nào các yếu tố bổ sung được thêm vào danh sách, Python tự động phân bổ bộ nhớ thêm để phù hợp với các yếu tố trong tương lai mà không cần thay đổi kích thước container.Điều này ngụ ý, việc thêm một phần tử duy nhất vào một danh sách trống sẽ kích động Python để phân bổ nhiều bộ nhớ hơn 8 byte.8 bytes.

Kích thước của danh sách trống trong Python là gì?

Và với độ dài của một danh sách trống là 0 Nó có thể được sử dụng để kiểm tra xem danh sách có trống trong Python không.0 it can be used to check if a list is empty in Python.

Python không sử dụng bao nhiêu bộ nhớ?

Nó chỉ ra rằng không ai tiêu thụ 16 byte và đó thực sự là quá nhiều chỉ đơn giản là một giá trị trống.16 bytes and that's actually too much for simply an empty value.

Một danh sách 10000 số nguyên của byte lấy trong Python?

Vì một số nguyên nhỏ sử dụng 28 byte, bây giờ chúng ta đã biết lý do tại sao một triệu số nguyên mất 28 MB RAM.Nhưng tại sao các số nguyên Python lại mất nhiều trí nhớ?Mỗi đối tượng trong triển khai Python mặc định, CPython, cũng là một cấu trúc pyobject C hoặc một trong các biến thể của nó.28 bytes, now we know why a million integers take 28MB of RAM. But why do Python integers take so much memory? Every object in the default Python implementation, CPython, is also a PyObject C struct or one of its variants.