eryksun đã trả lời câu hỏi số 1 và tôi đã trả lời câu hỏi số 3 (số 4 ban đầu), nhưng bây giờ hãy trả lời câu hỏi số 2:
Tại sao nó phát hành cụ thể 50,5mb - số tiền được phát hành dựa trên là bao nhiêu?
Cuối cùng, cái mà nó dựa vào là một chuỗi các sự trùng hợp ngẫu nhiên bên trong Python và malloc
điều đó rất khó dự đoán.
Đầu tiên, tùy thuộc vào cách bạn đo bộ nhớ, bạn chỉ có thể đo các trang thực sự được ánh xạ vào bộ nhớ. Trong trường hợp đó, bất cứ khi nào một trang bị hoán đổi bởi máy nhắn tin, bộ nhớ sẽ hiển thị dưới dạng "giải phóng", mặc dù nó không được giải phóng.
Hoặc bạn có thể đang đo các trang đang sử dụng, có thể hoặc không thể tính các trang được phân bổ nhưng không bao giờ chạm vào (trên các hệ thống phân bổ quá mức tối ưu, như linux), các trang được phân bổ nhưng được gắn thẻ MADV_FREE
, v.v.
Nếu bạn thực sự đang đo các trang được phân bổ (thực sự không phải là một điều rất hữu ích để làm, nhưng dường như đó là những gì bạn đang hỏi về) và các trang đã thực sự bị xử lý, hai trường hợp có thể xảy ra: Hoặc là bạn ' đã sử dụng brk
hoặc tương đương để thu nhỏ phân đoạn dữ liệu (rất hiếm hiện nay) hoặc bạn đã sử dụng munmap
hoặc tương tự để phát hành phân đoạn được ánh xạ. (Về lý thuyết cũng có một biến thể nhỏ cho biến thể thứ hai, trong đó có nhiều cách để phát hành một phần của phân đoạn được ánh xạ, ví dụ, đánh cắp nó với MAP_FIXED
một MADV_FREE
phân đoạn mà bạn lập tức hủy bỏ.)
Nhưng hầu hết các chương trình không phân bổ trực tiếp mọi thứ ra khỏi các trang bộ nhớ; họ sử dụng một malloc
cấp phát kiểu. Khi bạn gọi free
, bộ cấp phát chỉ có thể phát hành các trang cho HĐH nếu bạn tình cờ nhận được free
đối tượng trực tiếp cuối cùng trong ánh xạ (hoặc trong N trang cuối của phân đoạn dữ liệu). Không có cách nào ứng dụng của bạn có thể dự đoán hợp lý điều này, hoặc thậm chí phát hiện ra rằng nó đã xảy ra trước.
CPython làm cho điều này thậm chí còn phức tạp hơn nữa, nó có bộ cấp phát đối tượng 2 cấp tùy chỉnh ở trên bộ cấp phát bộ nhớ tùy chỉnh ở trên malloc
. (Xem các nhận xét nguồn để được giải thích chi tiết hơn.) Và trên hết, ngay cả ở cấp độ API C, ít Python hơn, bạn thậm chí không trực tiếp kiểm soát khi các đối tượng cấp cao nhất bị hủy.
Vì vậy, khi bạn phát hành một đối tượng, làm sao bạn biết liệu nó có giải phóng bộ nhớ cho HĐH không? Chà, trước tiên bạn phải biết rằng bạn đã phát hành tài liệu tham khảo cuối cùng (bao gồm bất kỳ tài liệu tham khảo nội bộ nào bạn chưa biết), cho phép GC phân bổ nó. (Không giống như các triển khai khác, ít nhất CPython sẽ phân bổ một đối tượng ngay khi được phép.) Điều này thường giải quyết ít nhất hai điều ở cấp độ tiếp theo (ví dụ: đối với một chuỗi, bạn đang giải phóng PyString
đối tượng và bộ đệm chuỗi ).
Nếu bạn thực hiện phân bổ một đối tượng, để biết liệu điều này có làm giảm cấp độ tiếp theo để phân bổ một khối lưu trữ đối tượng hay không, bạn phải biết trạng thái bên trong của cấp phát đối tượng, cũng như cách thức triển khai. (Rõ ràng điều đó không thể xảy ra trừ khi bạn giải quyết điều cuối cùng trong khối và thậm chí sau đó, điều đó có thể không xảy ra.)
Nếu bạn làm deallocate một khối lượng lưu trữ đối tượng, để biết liệu điều này gây ra một free
cuộc gọi, bạn phải biết tình trạng nội bộ của bộ cấp phát PyMem, cũng như cách nó được thực hiện. (Một lần nữa, bạn phải sắp xếp lại khối sử dụng cuối cùng trong một malloc
khu vực ed, và thậm chí sau đó, nó có thể không xảy ra.)
Nếu bạn thực hiện free
một malloc
vùng ed, để biết liệu điều này gây ra một munmap
hoặc tương đương (hoặc brk
), bạn phải biết trạng thái bên trong của nó malloc
, cũng như cách nó được thực hiện. Và cái này, không giống như những cái khác, rất đặc trưng cho nền tảng. (Và một lần nữa, bạn thường phải giải quyết việc sử dụng cuối cùng malloc
trong một mmap
phân khúc, và thậm chí sau đó, điều đó có thể không xảy ra.)
Vì vậy, nếu bạn muốn hiểu lý do tại sao nó lại phát hành chính xác 50,5mb, bạn sẽ phải theo dõi nó từ dưới lên. Tại sao malloc
hủy bỏ các trang có giá trị 50,5mb khi bạn thực hiện một hoặc nhiều free
cuộc gọi đó (có thể hơn một chút so với 50,5mb)? Bạn sẽ phải đọc nền tảng của bạn malloc
, sau đó đi bộ các bảng và danh sách khác nhau để xem trạng thái hiện tại của nó. (Trên một số nền tảng, nó thậm chí có thể sử dụng thông tin ở cấp hệ thống, rất khó có thể chụp mà không chụp ảnh hệ thống để kiểm tra ngoại tuyến, nhưng may mắn thay, đây thường không phải là vấn đề.) Và sau đó bạn phải làm điều tương tự ở 3 cấp độ trên đó.
Vì vậy, câu trả lời hữu ích duy nhất cho câu hỏi là "Bởi vì."
Trừ khi bạn đang thực hiện phát triển giới hạn tài nguyên (ví dụ: được nhúng), bạn không có lý do gì để quan tâm đến những chi tiết này.
Và nếu bạn đang thực hiện phát triển giới hạn tài nguyên, biết những chi tiết này là vô ích; bạn phải thực hiện một bước cuối cùng xung quanh tất cả các cấp độ đó và cụ thể mmap
là bộ nhớ bạn cần ở cấp ứng dụng (có thể với một cấp phát vùng cụ thể, đơn giản, được hiểu rõ về ứng dụng ở giữa).