11. Bộ cấp phát bộ nhớ

CPython phân bổ bộ nhớ liên tục. Mọi đối tượng số nguyên, đối tượng danh sách, khung, bộ dữ liệu, mảng nhập lệnh, bộ đệm chuỗi, đối tượng mã, ngoại lệ, mô-đun và hàm đều cần bộ nhớ. Hệ thống phân bổ tồn tại để thực hiện các phân bổ này nhanh chóng, có cấu trúc, có thể sửa lỗi và di động trên các nền tảng.

CPython không chỉ sử dụng một bộ cấp phát. Nó sử dụng một số miền và lớp cấp phát. Các đối tượng Python nhỏ thường đi qua bộ cấp phát đối tượng nhỏ chuyên dụng của CPython, trong khi các bộ đệm lớn hơn có thể đi qua bộ cấp phát nền tảng.

11.1 Tại sao CPython có bộ cấp phát riêng

Một chương trình Python tạo ra nhiều đối tượng có thời gian tồn tại ngắn.python for i in range(1_000_000): x = (i, i + 1) Vòng lặp này phân bổ nhiều đối tượng bộ và tham chiếu số nguyên. Nếu mọi phân bổ đối tượng nhỏ đều đi thẳng vào hệ thốngmalloc, chi phí sẽ cao.

Hệ thống cấp phát của CPython cải thiện điều này bằng cách:```text serving small object allocations quickly grouping small allocations into arenas and pools reducing calls into the platform allocator supporting debug hooks separating allocator domains making object allocation behavior predictable enough for internals work


## 11.2 Miền cấp phát

CPython phân b b nh thành các min.

Các min quan trng là:

| Tên min | S dng đin hình |
| ------------- | --------------------------------------------------- |
| B nh thô | B nh cp thp độc lp vi trng thái đối tượng Python |
| Ký c | B nh thi gian chy Python đa năng |
| B nh đối tượng | Phân b đối tượng Python |

 cp độ API C, chúng xut hin dưới dng h hàm:```c
PyMem_RawMalloc
PyMem_RawCalloc
PyMem_RawRealloc
PyMem_RawFree

PyMem_Malloc
PyMem_Calloc
PyMem_Realloc
PyMem_Free

PyObject_Malloc
PyObject_Calloc
PyObject_Realloc
PyObject_Free
```S khác bit rt quan trng vì mi min có th có các hook, ràng buc và hành vi g li khác nhau.

Mt quy tc đơn gin:```text
PyMem_Raw*
    use for memory that may be allocated without an initialized Python runtime

PyMem_*
    use for general Python memory

PyObject_*
    use for memory belonging to Python objects
```Mã m rng phi khp vi các hàm phân b và hàm t do trong cùng mt h.

Chính xác:```c
char *p = PyMem_Malloc(128);
if (p == NULL) {
    return PyErr_NoMemory();
}

/* use p */

PyMem_Free(p);
```Không đúng:```c
char *p = PyMem_Malloc(128);
free(p);                 /* wrong allocator family */
```Trn các h cp phát có th làm hng b nh.

## 11.3 Phân bổ đối tượng và khởi tạo đối tượng

Phân b d tr b nh. Vic khi to cung cp cho b nh đó mt trng thái đối tượng hp l.

Đối vi các đối tượng Python, s khác bit này rt quan trng.

Phân b đối tượng:```text
reserve memory for object layout
set object header
set type pointer
set reference count
possibly track with GC
```Khi to đối tượng:```text
fill fields
store references
validate arguments
establish invariants
```Đối vi lp do người dùng định nghĩa:```python
obj = MyClass(1, 2)
```quá trình thô là:```text
call type machinery
allocate memory for instance
initialize object header
call __new__
call __init__
return initialized object
```Đối vi các loi tin ích m rng C, vic phân b thường đi qua đối tượng loi:```c
self = (MyObject *)type->tp_alloc(type, 0);
```Sau đó khi to đin vào các trường.

## 11.4`tp_alloc`Và`tp_free`Mọi đối tượng loại có thể chỉ định cách phân bổ và giải phóng các thể hiện.

Khe cm loi quan trng:```text
tp_alloc
tp_free
tp_dealloc

tp_allocdự trữ bộ nhớ cho một đối tượng mới.tp_freegiải phóng bộ nhớ cho đối tượng.tp_dealloclà hàm hủy dành riêng cho loại. Nó thường giải phóng các trường và sau đó gọitp_free.

Hình dạng đơn giản:```c static void MyObject_dealloc(MyObject *self) { Py_XDECREF(self->value); Py_TYPE(self)->tp_free((PyObject *)self); }


S tách bit này cho phép các loi đối tượng khác nhau s dng các chiến lược phân b khác nhau trong khi vn duy trì vic dn dp theo tng loi c th mt cách rõ ràng.

## 11.5 Bộ phân bổ đối tượng nhỏ

B cp phát đối tượng nh ca CPython thường được gi là`pymalloc`.

Nó được ti ưu hóa cho các khi b nh nh được s dng bi các đối tượng Python.

V mt khái nim:```text
arena
    large region obtained from system allocator

pool
    fixed-size subdivision inside an arena

block
    one small allocation served to CPython
```H thng phân cp:```text
system allocator
    
arenas
    
pools
    
blocks
```Phân b nh được làm tròn thành các lp kích thước. Mt nhóm phc v các khi có cùng kích thước.

Điu này tránh vic yêu cu người cp phát h thng cho tng đối tượng nh.

## 11.6 Đấu trường

Mt đấu trường là mt vùng b nh ln thu được t b cp phát cơ bn.

V mt khái nim:```text
arena
    pool
    pool
    pool
    ...
```Đấu trường cho phép CPython qun lý nhiu vic phân b đối tượng nh theo đợt.

Khi CPython cn thêm b nh cho các đối tượng nh, nó s yêu cu mt đấu trường. Đấu trường đó được chia thành các h bơi. B bơi được s dng để phc v các khi.

Mt đấu trường ch có th được đưa tr li h thng khi tt c các nhóm bên trong nó tr nên min phí. Điu này có nghĩa là b nh có th vn được CPython dành riêng ngay c sau khi nhiu đối tượng b phá hy.

Hành vi đó có th khiến người dùng ngc nhiên:```text
objects were freed
process RSS did not immediately shrink
```Điu này không phi lúc nào cũng ch ra s rò r. B nh có th được b cp phát gi để tái s dng.

## 11.7 Bể bơi

B bơi là mt phn ca đấu trường.

Mi nhóm phc v mt lp kích thước khi ti mt thi đim.

Ví d:```text
pool A
    32-byte blocks

pool B
    64-byte blocks

pool C
    128-byte blocks
```Khi mt nhóm được gán cho mt lp kích thước, tt c các khi trong nhóm đó có cùng kích thước. Điu này làm cho vic phân b và hot động t do tr nên đơn gin.

B cp phát có th duy trì danh sách các nhóm có các khi có sn. Vic phân b mt đối tượng nh thường có nghĩa là ly khi có sn tiếp theo t mt nhóm.

## 11.8 Khối và lớp kích thước

Mt khi là b nh được tr v cho mt yêu cu cp phát.

Kích thước phân b nh được làm tròn thành các lp kích thước.

Khái nim ví d:```text
request 37 bytes
    rounded to 40 or 48 byte class depending on allocator rules

request 72 bytes
    rounded to matching size class

request too large
    bypass pymalloc and use larger allocator path
```Các lp kích thước chính xác ph thuc vào phiên bn CPython và cu hình bn dng.

Ý tưởng quan trng:```text
small requests use fixed-size pools
large requests use another allocator path
```Nhóm kích thước c định giúp phân b nhanh hơn và gim phân mnh bên trong khi lượng công vic đối tượng nh.

## 11.9 Danh sách miễn phí

Mt s loi đối tượng s dng danh sách min phí ngoài b cp phát chung.

Danh sách min phí lưu tr các đối tượng đã b phá hy gn đây thuc mt loi c th để chúng có th được s dng li nhanh chóng.

Các ví d ph biến trong lch s CPython bao gm các khung, b d liu có kích thước nht định, s float, danh sách và các đối tượng ni b khác, mc dù vic s dng danh sách min phí chính xác thay đổi theo phiên bn.

Dòng khái nim:```text
destroy object
    if type-specific free list has room:
        put object memory on free list
    else:
        return memory to allocator

create object
    if free list has cached object:
        reuse it
    else:
        allocate new memory
```Danh sách min phí đánh đổi kh năng gi b nh để ly tc độ.

Chúng có th thc hin vic phân b đối tượng nhanh hơn nhiu trong các vòng lp cht ch, nhưng chúng cũng có nghĩa là các đối tượng được gii phóng có th không tr li b nh ngay lp tc cho b cp phát.

## 11.10 Thực tập và tái sử dụng đối tượng

Mt s đối tượng được tái s dng có ch ý.

Ví d bao gm:```text
None
True
False
small integers
some strings
empty tuple
interned identifiers
```Vic tái s dng này làm gim áp lc phân b và cho phép so sánh nhanh hơn trong mt s đường dn ni b.

Ví d:```python
a = "name"
b = "name"
```Tùy thuc vào cách to chui, CPython có th thc hin chúng. Chui ni b rt hu ích cho các mã định danh, tên thuc tính và khóa t đin được s dng ni b.

Tái s dng đối tượng là mt s ti ưu hóa. Mã Python không nên da vào nhn dng đối tượng ngoi tr các tài liu đơn l như`None`, `True`, `False`, `NotImplemented`, Và`Ellipsis`.

Chính xác:```python
if value is None:
    ...
```Tránh xa:```python
if x is 1000:
    ...
```Th hai da vào hành vi tái s dng đối tượng c th khi trin khai.

## 11.11 Đối tượng bất tử và phân bổ

CPython hin đại s dng các đối tượng bt t cho các đối tượng thuc s hu thi gian chy được chn.

Mt vt th bt t được coi là sng vĩnh vin. Hot động đếm tham chiếu có th tránh được các hiu ng thông thường sut đời cho nó.

Điu này nh hưởng gián tiếp đến vic phân b:```text
some fundamental objects are allocated once
their lifetime is the runtime lifetime
normal deallocation never frees them
```Các ví d có th bao gm các đối tượng ging như singleton và các hng s bên trong được s dng li nhiu.

Đối vi tác gi tin ích m rng, quy tc không thay đổi:```text
use Py_INCREF and Py_DECREF
do not manually inspect or change ob_refcnt
do not assume ordinary deallocation for every object
```Mã đúng s hot động cho dù đối tượng là phàm nhân hay bt t.

## 11.12 Phân mảnh bộ nhớ

Phân mnh b nh xy ra khi b nh trng tn ti nhưng b chia thành nhiu phn không th đáp ng các yêu cu phân b ln hơn hoc không th tr li h điu hành mt cách sch s.

CPython có th b phân mnh  nhiu cp độ:```text
inside pymalloc pools
inside arenas
inside the system allocator
inside type-specific free lists
inside long-lived Python containers
```Mu ví d:```python
items = []
for i in range(1_000_000):
    items.append(bytearray(100))

del items
```Các đối tượng Python có th b hy, nhưng hành vi b nh ph thuc vào kích thước đối tượng, đường dn cp phát, mc độ đầy đủ ca trường, danh sách trng và hành vi cp phát h thng.

RSS có th duy trì  mc cao vì CPython d kiến ​​s s dng li b nh sau này.

## 11.13`tracemalloc`

`tracemalloc`theo dõi phân b b nh Python.

Ví d:```python
import tracemalloc

tracemalloc.start()

data = [str(i) for i in range(100_000)]

current, peak = tracemalloc.get_traced_memory()
print(current, peak)

tracemalloc.stop()
```Nó có th hin th nơi b nh được phân b:```python
import tracemalloc

tracemalloc.start()

data = [bytes(1024) for _ in range(1000)]

snapshot = tracemalloc.take_snapshot()
stats = snapshot.statistics("lineno")

for stat in stats[:10]:
    print(stat)

tracemallocrất hữu ích cho việc gỡ lỗi phân bổ cấp độ Python. Nó không hiển thị mọi phân bổ gốc được thực hiện bởi mọi thư viện C.

11.14 Móc phân bổ gỡ lỗi

CPython hỗ trợ các hook bộ nhớ gỡ lỗi giúp phát hiện việc sử dụng sai mục đích cấp phát.

Bản dựng gỡ lỗi và chế độ cấp phát gỡ lỗi có thể phát hiện các sự cố như:```text writing before allocated memory writing after allocated memory using memory after free freeing memory with wrong allocator family double free uninitialized memory patterns


Móc g li thường thêm các byte đệm xung quanh phân b và lp đầy b nh bng các mu byte có th nhn dng được.

Điu này làm cho vic phát hin li b nh  gn ngun d dàng hơn.

## 11.15 Kỷ luật gia đình người phân bổ

K lut gia đình Allocator rt nghiêm khc.

Các cp đúng:

| Phân b | Min phí |
| ----------------- | --------------- |
|`PyMem_RawMalloc` | `PyMem_RawFree` |
| `PyMem_Malloc`    | `PyMem_Free`    |
| `PyObject_Malloc` | `PyObject_Free` |
| `malloc`          | `free`|

Ghép ni không chính xác là li:```c
void *p = PyObject_Malloc(64);
PyMem_Free(p);              /* wrong */
```Cũng sai:```c
void *p = malloc(64);
PyObject_Free(p);           /* wrong */
```B cp phát to b nh phi là b cp phát gii phóng b nh.

## 11.16 Phân bổ bộ đệm trong mã mở rộng

Đối vi các b đệm không phi đối tượng, hãy ưu tiên h cp phát Python thích hp.

Ví d:```c
typedef struct {
    PyObject_HEAD
    char *data;
    Py_ssize_t size;
} BufferObject;
```Phân b:```c
self->data = PyMem_Malloc(size);
if (self->data == NULL) {
    PyErr_NoMemory();
    return -1;
}
self->size = size;
```Phân b:```c
static void
Buffer_dealloc(BufferObject *self)
{
    PyMem_Free(self->data);
    Py_TYPE(self)->tp_free((PyObject *)self);
}
```B đệm s dng`PyMem_*`. Bn thân đối tượng s dng kiu`tp_alloc`Và`tp_free`.

Hãy gi nhng kiếp sng này riêng bit.

## 11.17 Bộ nhớ đối tượng và các tài liệu tham khảo có chứa

Vic cp phát b nh đối tượng không t động qun lý các tham chiếu Python có trong đó.

Ví d:```c
typedef struct {
    PyObject_HEAD
    PyObject *value;
} BoxObject;
```Phân b cung cp b nh cho`value`, nhưng nó chưa s hu mt tài liu tham kho hp l.

Vic khi to phi thiết lp nó mt cách an toàn:```c
self->value = NULL;
```Sau đó gán tài liu tham kho s hu vi`Py_INCREF`hoc bng cách nhn được tài liu tham kho b đánh cp/mi theo hp đồng API.

Deallocation phi phát hành tham chiếu s hu:```c
Py_XDECREF(self->value);
```Cp phát b nh và quyn s hu tham chiếu là các h thng có liên quan nhưng riêng bit.

## 11.18 Lỗi phân bổ

B phân b có th tht bi.

Mã m rng C phi kim tra kết qu phân b.```c
void *p = PyMem_Malloc(size);
if (p == NULL) {
    PyErr_NoMemory();
    return NULL;
}
```Đối vi các hàm to đối tượng,`NULL`thường có nghĩa là mt ngoi l đã được đặt hoc phi được đặt.

Đúng mu:```c
PyObject *obj = PyLong_FromLong(42);
if (obj == NULL) {
    return NULL;
}
```Đừng bao gi cho rng vic phân b thành công. Mã Python có th chy dưới áp lc b nh, môi trường nhúng, vùng cha b hn chế hoc kim tra làm m.

## 11.19 Tái phân bổ`PyMem_Realloc`thay đổi kích thước của khối bộ nhớ.

Mu:```c
char *new_data = PyMem_Realloc(self->data, new_size);
if (new_data == NULL) {
    PyErr_NoMemory();
    return -1;
}

self->data = new_data;
self->size = new_size;
```Không ghi đè lên con tr ban đầu trước khi kim tra thành công.

Không đúng:```c
self->data = PyMem_Realloc(self->data, new_size);
if (self->data == NULL) {
    return -1;       /* old pointer lost */
}
```Nếu vic phân b li không thành công, vic phân b ban đầu vn hp l. Mt con tr đó s làm rò r b nh.

## 11.20 Phân bổ quá mức

Mt s vùng cha phân b quá mc để tránh phân b li trên mi phn b sung.

Danh sách là ví d tiêu chun.```python
xs = []
for i in range(100):
    xs.append(i)
```Danh sách không phân b chính xác mt v trí mi cho mi phn b sung. Nó phát trin công sut theo các bước ln hơn.

V mt khái nim:```text
length = number of used entries
allocated = number of available slots
```Khi độ dài đạt đến dung lượng được phân b, CPython s tăng mng vt phm.

Điu này mang li hành vi b sung hiu qu được khu hao.

Đánh đổi:```text
fewer reallocations
some unused spare capacity
```## 11.21 Thu nhỏ vùng chứa

Các vùng cha có th không tr li b nh ngay lp tc khi chúng co li.

Ví d:```python
xs = list(range(1_000_000))
del xs[:900_000]
```Độ dài logic gim. Năng lc bên trong ch có th co li trong nhng điu kin nht định.

Điu này tránh được vic tái phân b tn kém khi danh sách thu hp li và phát trin liên tc.

Đối vi mã nhy cm vi b nh, vic to mt vùng cha nh gn mi đôi khi có th giúp:```python
xs = xs[:]
```hoc:```python
xs = list(xs)
```Nhưng hãy đo trước. Vic sao chép có th tn kém.

## 11.22 Chế độ xem bộ nhớ và bộ đệm

Mt s đối tượng hin th b nh thông qua giao thc b đệm.

Ví d:```text
bytes
bytearray
array.array
memoryview
mmap objects
NumPy arrays
some extension objects
```Trình xut b đệm có th hin th b nh thô cho mt đối tượng khác. Điu đó to ra nhng hn chế sut đời.

Ví d:```python
b = bytearray(b"hello")
v = memoryview(b)
```Trong khi chế độ xem b nh tn ti, vic thay đổi kích thước bytearray cơ bn có th b hn chế.

 cp độ C, nhà xut b đệm phi đảm bo b nh vn hp l trong khi người tiêu dùng gi chế độ xem b đệm.

Điu này liên quan đến b cp phát vì b nh không th được gii phóng hoc di chuyn trong khi chế độ xem bên ngoài ph thuc vào nó.

## 11.23 Hậu quả của việc phân bổ không di chuyển

Con tr đối tượng ca CPython n định. Các đối tượng thường không được di chuyn bi b thu gom rác nén.

Hu qu:```text
PyObject * pointers remain valid while references are owned
C extensions can store object pointers
id(obj) can be address-like in CPython
memory cannot be compacted by moving live objects
fragmentation can accumulate
```Thiết kế không chuyn động là trng tâm ca kh năng tương thích API C.

Nó cũng gii thích ti sao CPython s dng đấu trường, nhóm, danh sách min phí và phân lp phân b cn thn thay vì nén mt đống.

## 11.24 Tùy chỉnh bộ phân bổ

CPython cho phép các trình nhúng và môi trường chuyên dng tùy chnh b cp phát.

Điu này hu ích cho:```text
embedding Python in another application
sandboxing
memory accounting
debugging
custom allocation strategies
instrumentation
constrained runtimes
```Vic tùy chnh b cp phát phi din ra cn thn và thường sm trong quá trình khi to thi gian chy.

B cp phát thay thế phi tuân theo k vng ca CPython đối vi tng min ca b cp phát.

Móc cp phát xu có th làm hng trình thông dch.

## 11.25 Tính toán bộ nhớ khó

Vic hiu cách s dng b nh Python rt khó vì có nhiu lp tương tác vi nhau.

Mt đối tượng Python có th liên quan đến:```text
object header
object payload
auxiliary arrays
referenced objects
allocator padding
pool overhead
arena overhead
free-list retention
system allocator metadata
native library allocations
```Ví d:```python
xs = ["abc" for _ in range(1000)]
```B nh bao gm:```text
list object
list item array
1000 references in the array
string objects
string character data
allocator overhead
possibly interned or reused objects

sys.getsizeof(xs)chỉ báo cáo kích thước của đối tượng danh sách và bộ nhớ ngay lập tức của nó chứ không phải biểu đồ bắc cầu đầy đủ.

11.26sys.getsizeof

sys.getsizeoftrả về kích thước của một đối tượng như được đối tượng đó báo cáo.```python import sys

xs = [1, 2, 3] print(sys.getsizeof(xs))


Ví d:```python
import sys

xs = [[1], [2], [3]]

print(sys.getsizeof(xs))
```Điu này bao gm lưu tr ca danh sách bên ngoài, không phi danh sách bên trong và ni dung ca chúng.

Hàm kích thước đệ quy phi duyt qua các tham chiếu mt cách cn thn và tránh tính hai ln các đối tượng dùng chung.

## 11.27 Các mẫu phân bổ phổ biến

Các mu phân b CPython ph biến bao gm:

| Mu | Ví d | Hành vi phân b |
| ------------------- | -------------- | -------------------------------------------- |
| Nhiu b d liu nh | trình phân tích cú pháp, công vic AST, vòng lp | vn đề cp phát đối tượng nh và danh sách min phí |
| Đối tượng byte ln | I/O, tun t hóa | có th b qua b cp phát đối tượng nh |
| Danh sách ngày càng tăng | mã nng ni thêm | vn đề phân b quá mc |
| Nhng câu nói ln | lp ch mc, JSON, toàn cu | vn đề tăng trưởng bng băm |
| Khung | gi hàm | vn đề phân b và tái s dng khung |
| Ngoi l | đường dn nhiu li | vn đề truy nguyên và lưu gi khung |
| Dây | định danh, phân tích cú pháp | B cc Unicode và vn đề thc tp |

Công vic biu din thường bt đầu bng vic tìm ra khuôn mu nào chiếm ưu thế.

## 11.28 Quy tắc phân bổ tiện ích mở rộng C

Các quy tc thc tế dành cho tác gi phn m rng:

| Tình hung | Quy tc |
| ----------------------------------- | -------------------------------------- |
| Phân b phiên bn đối tượng Python | S dng máy phân b loi |
| Gii phóng phiên bn đối tượng Python | S dng`tp_free`t người gii quyết |
| Phân b b nh thi gian chy ph tr | S dng`PyMem_*`hoc gia đình có giy t |
| Phân b b nh đối tượng theo cách th công | S dng`PyObject_*`ch khi thích hp |
| Tr v đối tượng Python | Tr li tài liu tham kho thuc s hu |
| Lưu tr trường đối tượng Python | S hu mt tài liu tham kho |
| Tái phân b b nh | Gi con tr cũ cho đến khi thành công |
| X lý li phân b | Đặt hoc truyn bá`MemoryError`|
| Trn phân b | Đừng làm điu đó |

Li cp phát thường nghiêm trng. Chúng có th xut hin dưới dng s c khác xa vi li thc tế.

## 11.29 Mô hình tinh thần

S dng mô hình này:```text
Python object allocation
    type object chooses allocation path
    object memory contains common header
    object-specific fields are initialized
    references are owned explicitly
    deallocator releases references
    tp_free releases memory

Small-object allocation
    arenas contain pools
    pools contain fixed-size blocks
    small requests are served quickly
    memory may be retained for reuse
```Qun lý b nh trong CPython là mt h thng phân lp:```text
reference counting decides when an object dies
cyclic GC finds unreachable cycles
deallocator releases object-owned resources
allocator reuses or frees memory blocks
system allocator manages process heap pages
operating system manages virtual memory
```Mi lp tr li mt câu hi khác nhau.

##11.30 Tóm tắt

H thng cp phát b nh ca CPython h tr phân b nhanh cho khi lượng công vic nng v đối tượng ca các chương trình Python. Các đồ vt nh thường được phc v thông qua`pymalloc`, t chc b nh thành các đấu trường, nhóm và khi. Danh sách min phí theo loi c th và tái s dng đối tượng tiếp tc gim chi phí phân b cho các đối tượng ph biến.

Đối vi các tác gi tin ích m rng C, các quy tc quan trng là k lut nhóm cp phát, x lý chính xác li phân b, phân b li an toàn và phân tách rõ ràng gia quyn s hu b nh và quyn s hu tham chiếu.

B nh được gii phóng  cp đối tượng Python có th được d tr bên trong CPython hoc b cp phát nn tng. RSS cao sau khi xóa đối tượng không t động có nghĩa là b rò r. CPython thường gi sn b nh để s dng li.