Hướng dẫn why is python automatic memory management? - tại sao python quản lý bộ nhớ tự động?
Quản lý bộ nhớ là quá trình quản lý hiệu quả bộ nhớ máy tính (RAM). Nó liên quan đến việc phân bổ một phần bộ nhớ vào thời gian chạy cho chương trình khi chương trình yêu cầu và giải phóng bộ nhớ được phân bổ để sử dụng lại khi chương trình không còn cần nó nữa. Show
Trong các ngôn ngữ như C hoặc Rust, quản lý bộ nhớ là trách nhiệm của lập trình viên. Lập trình viên phải phân bổ thủ công bộ nhớ trước khi chương trình có thể sử dụng và phát hành nó khi chương trình không còn cần nó nữa. Trong Python, quản lý bộ nhớ là tự động! Python tự động xử lý việc phân bổ và giải quyết bộ nhớ. Trong bài viết này, chúng tôi sẽ thảo luận về các phần bên trong của quản lý bộ nhớ trong Python. Chúng tôi cũng sẽ đề cập đến cách các đơn vị cơ bản, chẳng hạn như các đối tượng, được lưu trữ trong bộ nhớ, các loại phân bổ bộ nhớ khác nhau trong Python và cách trình quản lý bộ nhớ của Python quản lý bộ nhớ một cách hiệu quả. Hiểu nội bộ của quản lý bộ nhớ trong Python giúp thiết kế các ứng dụng hiệu quả bộ nhớ. Nó cũng giúp dễ dàng gỡ lỗi các vấn đề bộ nhớ trong một ứng dụng. Mục lục
Hãy bắt đầu với việc hiểu Python như một đặc điểm kỹ thuật ngôn ngữ và sau đó đi sâu vào Cpython! Python như một đặc điểm kỹ thuật ngôn ngữ
Các hàm 8 và 9 trong C là gì?Đối tượng trong Python Các biến trong Python Quản lý bộ nhớ trong CPythonBộ phân bổ bộ nhớ
Khối Hồ bơi Đấu trường Liệu một quá trình Python có phát hành bộ nhớ không? Bộ sưu tập rác trong PythonSố lượng tham chiếu Bộ sưu tập rác trên cơ sở số lượng tham chiếu Tài liệu tham khảo theo chu kỳ trong Python Bộ sưu tập rác thế hệ Đối tượng trong PythonCác biến trong Python Mỗi đối tượng Python bao gồm ba trường:
Hãy xem xét một ví dụ đơn giản: Khi mã trên được thực thi, CPython sẽ tạo một đối tượng loại 3 và phân bổ bộ nhớ cho đối tượng này trên bộ nhớ heap. 4 chỉ ra loại đối tượng trong CPython và trường 5, như tên cho thấy, lưu trữ giá trị của đối tượng ( 6 trong trường hợp này). Chúng tôi sẽ thảo luận về lĩnh vực 7 sau trong bài viết.Các biến trong PythonCác biến trong Python chỉ là các tham chiếu đến đối tượng thực tế trong bộ nhớ. Chúng giống như tên hoặc nhãn trỏ đến đối tượng thực tế trong bộ nhớ. Họ không lưu trữ bất kỳ giá trị nào. Xem xét ví dụ sau: Như đã thảo luận trước đó, khi mã trên được thực thi, CPython bên trong tạo ra một đối tượng của số nguyên loại. Biến 8 trỏ đến đối tượng số nguyên này như được hiển thị bên dưới:Chúng ta có thể truy cập đối tượng số nguyên trong chương trình Python bằng cách sử dụng biến 8.Hãy gán đối tượng số nguyên này cho một biến khác 0:Khi mã trên được thực thi, các biến 8 và 0 đều trỏ đến cùng một đối tượng số nguyên, như được hiển thị bên dưới:Bây giờ chúng ta hãy tăng giá trị của đối tượng số nguyên bằng 1:
Khi mã trên được thực thi, CPython sẽ tạo một đối tượng số nguyên mới với giá trị 3 và tạo biến 8 trỏ đến đối tượng số nguyên mới này. Biến 0 sẽ tiếp tục trỏ đến đối tượng số nguyên với giá trị 6, như được hiển thị bên dưới:Ở đây, chúng ta có thể thấy rằng thay vì ghi đè giá trị của 6 với 3, CPython tạo ra một đối tượng mới với giá trị 3 vì các số nguyên trong Python là bất biến. Sau khi được tạo, chúng không thể được sửa đổi. Xin lưu ý rằng các loại dữ liệu nổi và chuỗi cũng không thể thay đổi trong Python.Hãy xem xét một chương trình Python đơn giản để giải thích thêm về khái niệm này:
Mã trên xác định một vòng lặp 0 đơn giản tăng giá trị của biến 1 cho đến khi nó nhỏ hơn 6. Khi mã này được thực thi, với mỗi lần tăng của biến 1, cpython sẽ tạo một đối tượng số nguyên mới với giá trị được tăng lên và đối tượng số nguyên cũ sẽ bị xóa (chính xác hơn, đối tượng này sẽ đủ điều kiện để xóa) khỏi bộ nhớ .CPYThon gọi phương thức 8 cho mỗi đối tượng mới để phân bổ bộ nhớ cho đối tượng đó. Nó gọi phương thức 9 để xóa đối tượng cũ khỏi bộ nhớ.Hãy chuyển đổi mã trên theo các điều khoản của 8 và 9:
Chúng ta có thể thấy rằng Cpython tạo và xóa một số lượng lớn các đối tượng, ngay cả đối với chương trình đơn giản này. Nếu chúng tôi gọi các phương thức 8 và 9 cho mỗi lần tạo và xóa đối tượng, nó sẽ làm giảm hiệu suất thực hiện của chương trình và làm cho chương trình chậm.Do đó, CPython giới thiệu các kỹ thuật khác nhau để giảm số lần chúng ta phải gọi 8 và 9 cho mỗi lần tạo và xóa đối tượng nhỏ. Bây giờ hãy hiểu cách CPython quản lý bộ nhớ!Quản lý bộ nhớ trong CPythonQuản lý bộ nhớ trong Python liên quan đến việc quản lý một đống riêng tư. Một đống riêng tư là một phần của bộ nhớ dành riêng cho quá trình Python. Tất cả các đối tượng Python và cấu trúc dữ liệu được lưu trữ trong đống riêng tư. Hệ điều hành không thể phân bổ phần bộ nhớ này cho một quá trình khác. Kích thước của đống riêng có thể phát triển và thu nhỏ dựa trên các yêu cầu bộ nhớ của quá trình Python. Các đống riêng tư được quản lý bởi Trình quản lý bộ nhớ Python được xác định bên trong mã CPython. Đối với mục đích đại diện, đống riêng tư trong CPython có thể được chia thành nhiều phần như hình dưới đây: Xin lưu ý rằng ranh giới của mỗi phần này không cố định và có thể phát triển hoặc thu nhỏ dựa trên yêu cầu.
Khi chương trình yêu cầu bộ nhớ, CPython sử dụng phương thức 8 để yêu cầu bộ nhớ đó từ hệ điều hành và đống riêng tư tăng kích thước.Để tránh gọi 8 và 9 cho mỗi lần tạo và xóa đối tượng nhỏ, CPython xác định nhiều người phân bổ và người bán hàng cho các mục đích khác nhau. Chúng tôi sẽ thảo luận chi tiết về từng người trong số họ trong phần tiếp theo!Bộ phân bổ bộ nhớĐể tránh gọi các phương thức 8 và 9 thường xuyên, CPython xác định một hệ thống phân cấp của các trình phân bổ, như được hiển thị bên dưới:Đây là hệ thống phân cấp của các bộ phân bổ bộ nhớ từ cấp cơ sở:
Ở cấp độ cơ sở là bộ phân bổ 8. Phân bổ 8 là phương pháp 8 của ngôn ngữ C cho CPython. Nó chịu trách nhiệm tương tác với Trình quản lý bộ nhớ ảo của hệ điều hành và phân bổ bộ nhớ cần thiết cho quy trình Python. Đây là người phân bổ duy nhất giao tiếp với Trình quản lý bộ nhớ ảo của hệ điều hành.Ở đầu bộ phân bổ 8 là trình phân bổ 2 của Python. Bộ phân bổ 2 cung cấp một sự trừu tượng hóa cho bộ phân bổ 8 (tức là, phương pháp 8). Khi quá trình Python cần bộ nhớ, trình phân bổ 2 tương tác với trình phân bổ 8 để cung cấp bộ nhớ cần thiết. Nó đảm bảo rằng có đủ bộ nhớ để lưu trữ tất cả dữ liệu của quy trình Python.Trên đầu trang 2, chúng tôi có trình phân bổ đối tượng. Bộ phân bổ này được sử dụng để phân bổ bộ nhớ cho các đối tượng nhỏ (nhỏ hơn hoặc bằng 512 byte). Nếu một đối tượng cần hơn 512 byte bộ nhớ, Trình quản lý bộ nhớ của Python trực tiếp gọi Trình phân bổ 2.Như đã thấy trong biểu diễn trên, chúng ta có các phân bổ dành riêng cho đối tượng trên đầu của bộ phân bổ đối tượng. Các loại dữ liệu đơn giản, chẳng hạn như số nguyên, float, chuỗi và danh sách, có các phân bổ dành riêng cho đối tượng tương ứng. Các phân bổ dành riêng cho đối tượng này thực hiện các chính sách quản lý bộ nhớ theo yêu cầu của đối tượng. Ví dụ, bộ phân bổ dành riêng cho đối tượng cho số nguyên có một triển khai khác với bộ phân bổ dành riêng cho đối tượng cho float. Cả hai bộ phân bổ và phân bổ đối tượng dành riêng cho đối tượng đều hoạt động trên bộ nhớ đã được phân bổ cho quy trình Python bằng bộ phân bổ bộ nhớ thô. Những người phân bổ này không bao giờ yêu cầu bộ nhớ từ hệ điều hành. Họ hoạt động trên đống riêng tư. Nếu bộ phân bổ đối tượng hoặc bộ phân bổ dành riêng cho đối tượng cần nhiều bộ nhớ hơn, bộ phân bổ bộ nhớ thô của Python cung cấp nó bằng cách tương tác với bộ phân bổ đa năng. Phân cấp phân cấp bộ nhớ trong PythonKhi một đối tượng yêu cầu bộ nhớ và đối tượng có trình phân bổ dành riêng cho đối tượng được xác định, các phân bổ dành riêng cho đối tượng được sử dụng để phân bổ bộ nhớ. Nếu đối tượng không có trình phân bổ dành riêng cho đối tượng và hơn 512 byte bộ nhớ được yêu cầu, trình quản lý bộ nhớ Python trực tiếp gọi bộ phân bổ bộ nhớ thô để phân bổ bộ nhớ. Nếu kích thước bộ nhớ được yêu cầu nhỏ hơn 512 byte, các bộ phân bổ đối tượng được sử dụng để phân bổ nó. Người phân bổ đối tượngBộ phân bổ đối tượng cũng được gọi là 0. Nó được sử dụng để phân bổ bộ nhớ cho các đối tượng nhỏ có kích thước nhỏ hơn 512 byte.Cơ sở mã Cpython mô tả Trình phân bổ đối tượng là
Khi một đối tượng nhỏ yêu cầu bộ nhớ, thay vì chỉ phân bổ bộ nhớ cho đối tượng đó, trình phân bổ đối tượng yêu cầu một khối bộ nhớ lớn từ hệ điều hành. Khối bộ nhớ lớn này sau đó được sử dụng để phân bổ bộ nhớ cho các đối tượng nhỏ khác. Bằng cách này, người phân bổ đối tượng tránh gọi 8 cho mỗi đối tượng nhỏ.Khối bộ nhớ lớn mà bộ phân bổ đối tượng phân bổ được gọi là 2. Đấu trường có kích thước 256 kb.Để sử dụng 3 một cách hiệu quả, cpython chia 2 thành 5. Hồ bơi là 4 kb. Vì vậy, một 6 có thể bao gồm 64 nhóm (256kb / 4kb).Các hồ bơi được chia thành 7.Tiếp theo, chúng tôi sẽ thảo luận về từng thành phần này! KhốiCác khối là đơn vị nhỏ nhất của bộ nhớ mà bộ phân bổ đối tượng có thể phân bổ cho một đối tượng. Một khối có thể được phân bổ cho chỉ một đối tượng và một đối tượng chỉ có thể được phân bổ cho một khối. Không thể đặt các phần của một đối tượng trong hai hoặc nhiều khối riêng biệt. Các khối có sẵn trong các kích cỡ khác nhau. Kích thước nhỏ nhất của một khối là 8 byte, trong khi kích thước tối đa của một khối là 512 byte. Kích thước của một khối là bội số của 8, và do đó, kích thước khối có thể là 8, 16, 32, ..., 504 hoặc 512 byte. Mỗi kích thước khối được gọi là lớp kích thước. Có 64 lớp kích thước, như được hiển thị dưới đây: Như đã thấy trong bảng trên, các khối lớp 0 có kích thước có kích thước 8 byte, trong khi kích thước khối lớp 1 có kích thước 16 byte, v.v. Các chương trình luôn được phân bổ một khối đầy đủ hoặc không có khối nào cả. Vì vậy, nếu một chương trình yêu cầu 14 byte bộ nhớ, nó được phân bổ một khối 16 byte. Tương tự, nếu một chương trình yêu cầu 35 byte bộ nhớ, một khối 40 byte được phân bổ. Hồ bơiMột hồ bơi bao gồm các khối chỉ có một lớp kích thước. Ví dụ: một nhóm có khối kích thước lớp 0 không thể có các khối của bất kỳ lớp kích thước nào khác. Kích thước của nhóm bằng kích thước của trang bộ nhớ ảo. Ở đây 'Trang bộ nhớ ảo thuật ngữ có nghĩa là gì:
Trong hầu hết các trường hợp, kích thước của hồ bơi là 4 kb. Các hồ bơi chỉ được chạm khắc từ các đấu trường khi không có hồ bơi nào khác có một khối của lớp kích thước được yêu cầu. Một hồ bơi có thể ở một trong ba tiểu bang:
Các nhóm được xác định trong mã Cpython như hình dưới đây:
Thuật ngữ 1 chỉ ra lớp kích thước của nhóm. Nếu 1 là 0 cho một nhóm, nó sẽ chỉ có các khối kích thước lớp 0 (nghĩa là, các khối 8 byte).Thuật ngữ 3 chỉ ra đấu trường mà nhóm thuộc về.Các nhóm có cùng lớp kích thước được liên kết với nhau bằng danh sách được liên kết gấp đôi. Con trỏ 4 trỏ đến nhóm tiếp theo của cùng một lớp kích thước, trong khi con trỏ 5 trỏ đến nhóm trước đó có cùng lớp kích thước.Đây là cách các nhóm có cùng lớp được kết nối: Con trỏ 6 chỉ vào đầu danh sách các khối miễn phí được liên kết đơn lẻ trong nhóm. Khi một khối được phân bổ được giải phóng, nó được chèn ở phía trước của con trỏ 6.Như đã thấy trong hình trên, các khối 8 được phân bổ cho các đối tượng, trong khi các khối 9 được phân bổ cho các đối tượng nhưng bây giờ là miễn phí và có thể được phân bổ cho các đối tượng mới.Khi một yêu cầu được thực hiện cho bộ nhớ và không có nhóm nào có khối lớp kích thước được yêu cầu, CPython khắc một nhóm mới từ đấu trường. Khi một hồ bơi mới được chạm khắc, toàn bộ hồ bơi không được phân mảnh ngay lập tức thành các khối. Các khối được chạm khắc từ hồ bơi khi cần thiết. Vùng bóng mờ 00 của hồ bơi trong hình trên cho thấy các phần này của nhóm chưa được phân mảnh thành các khối.Một đoạn trích từ cơ sở mã Cpython đề cập đến các khối khắc từ nhóm như sau:
Ở đây, chúng ta có thể thấy rằng khi một hồ bơi mới được chạm khắc từ một đấu trường, chỉ có hai khối đầu tiên được chạm khắc từ hồ bơi. Một khối được phân bổ cho đối tượng yêu cầu bộ nhớ, trong khi khối còn lại miễn phí hoặc không bị ảnh hưởng và con trỏ 6 trỏ đến khối này.CPython duy trì một mảng có tên 02 để theo dõi các nhóm ở trạng thái 8 (các nhóm có sẵn để phân bổ) của tất cả các lớp kích thước.Chỉ số của mảng 02 bằng với lớp kích thước của nhóm. Đối với mỗi chỉ mục 1 của mảng 02, 07 chỉ vào tiêu đề của các nhóm có kích thước lớp 1. Ví dụ, 09 chỉ vào tiêu đề của các nhóm có kích thước lớp 10 và 11 chỉ vào tiêu đề của các nhóm có kích thước lớp 12.Hình dưới đây sẽ giúp dễ hiểu hơn: Vì các nhóm có cùng lớp có cùng kích thước được liên kết với nhau bằng danh sách được liên kết gấp đôi, tất cả các nhóm trong trạng thái 8 của mỗi lớp kích thước có thể được đi qua bằng cách sử dụng mảng 02.Nếu 07 chỉ vào 16, điều đó có nghĩa là không có nhóm có kích thước lớp 1 ở trạng thái 8. Nếu một đối tượng yêu cầu một khối có kích thước lớp 1, CPython sẽ khắc một nhóm mới có kích thước lớp 1 và cập nhật 07 để trỏ đến nhóm mới này.Nếu một khối được giải phóng khỏi một nhóm ở trạng thái 9, trạng thái hồ bơi sẽ thay đổi từ 9 thành 8. Cpython thêm nhóm này vào mặt trước của danh sách liên kết gấp đôi của các nhóm thuộc lớp kích thước của nó.Như đã thấy trong hình trên, 25 có kích thước lớp 10 và nó ở trạng thái 9. Khi một khối được giải phóng khỏi 25, trạng thái của nó thay đổi từ 9 thành 8. Khi trạng thái của 25 trở thành 8, CPython thêm nhóm này vào mặt trước của danh sách các nhóm có kích thước có kích thước 10 và 09 sẽ bắt đầu chỉ vào nhóm này.Đấu trườngĐấu trường là các khối bộ nhớ lớn được sử dụng để phân bổ bộ nhớ cho các đối tượng nhỏ. Chúng được phân bổ bởi bộ phân bổ bộ nhớ thô với kích thước 256 kb. Khi một đối tượng nhỏ yêu cầu bộ nhớ, nhưng không có đấu trường hiện có nào để xử lý yêu cầu này, thay vì chỉ yêu cầu bộ nhớ cho đối tượng nhỏ này, bộ phân bổ bộ nhớ thô yêu cầu một khối bộ nhớ lớn (256 kb) từ hệ điều hành. Những khối bộ nhớ lớn này được gọi là đấu trường. Các hồ bơi (kích thước 4 kb) được chạm khắc từ các đấu trường khi cần thiết. Hãy xem xét 35, như được định nghĩa trong cơ sở mã Cpython:
Con trỏ 36 chỉ vào danh sách các nhóm miễn phí và các nhóm miễn phí không có bất kỳ khối nào được phân bổ.Thuật ngữ 37 chỉ ra số lượng nhóm miễn phí trong đấu trường.CPython duy trì một danh sách được liên kết gấp đôi có tên là 38 để theo dõi tất cả các đấu trường với các nhóm 39.Các nhóm 40 ở trạng thái 0 hoặc 8.Con trỏ 43 trỏ đến đấu trường có thể sử dụng tiếp theo, trong khi con trỏ 44 trỏ đến đấu trường có thể sử dụng trước đó trong danh sách liên kết gấp đôi 38. Danh sách liên kết gấp đôi được sắp xếp theo thứ tự ngày càng tăng của giá trị 37.Như được hiển thị ở trên, 38 được sắp xếp trên cơ sở 37. Đấu trường với 0 nhóm miễn phí là mục đầu tiên, tiếp theo là đấu trường với 1 nhóm miễn phí, v.v. Nó có nghĩa là danh sách được sắp xếp với các đấu trường được phân bổ nhiều nhất trước tiên. Chúng tôi sẽ giải thích lý do tại sao việc sắp xếp này được nhập trong phần tiếp theo của bài viết.Danh sách đấu trường có thể sử dụng được sắp xếp dựa trên những gì có phân bổ nhiều nhất, vì vậy khi có yêu cầu phân bổ bộ nhớ, nó được phục vụ từ đấu trường với nhiều phân bổ nhất. Liệu một quá trình Python có phát hành bộ nhớ không?Khi một khối được phân bổ trong một nhóm được giải phóng, CPython không đưa bộ nhớ trở lại hệ điều hành. Bộ nhớ này tiếp tục thuộc về quy trình Python và CPython sử dụng khối này để phân bổ bộ nhớ cho các đối tượng mới. Ngay cả khi tất cả các khối trong một nhóm được giải phóng, CPython không trả lại bất kỳ bộ nhớ nào từ nhóm đến hệ điều hành. CPython giữ bộ nhớ của toàn bộ hồ bơi dành riêng cho việc sử dụng riêng. CPYThon phát hành bộ nhớ trở lại hệ điều hành ở cấp độ của đấu trường, không phải ở cấp độ khối hoặc nhóm. Ngoài ra, xin lưu ý rằng Cpython phát hành bộ nhớ của toàn bộ đấu trường cùng một lúc. Vì bộ nhớ chỉ có thể được phát hành ở cấp độ đấu trường, Cpython tạo ra đấu trường từ phần bộ nhớ mới chỉ khi nó hoàn toàn cần thiết! Nó luôn cố gắng phân bổ bộ nhớ từ các khối được chạm khắc và hồ bơi trước đó. Đây là lý do 38 được sắp xếp theo thứ tự giảm của 37. Yêu cầu tiếp theo cho bộ nhớ sẽ được phân bổ từ các đấu trường với nhiều phân bổ nhất. Điều này cho phép các đấu trường có dữ liệu ít nhất trở nên miễn phí nếu các đối tượng chúng chứa bị xóa và bộ nhớ bị chiếm bởi các đấu trường này có thể được phát hành cho hệ điều hành.Bộ sưu tập rác trong PythonBộ sưu tập rác được định nghĩa là quá trình cải tạo hoặc phát hành bộ nhớ được phân bổ khi chương trình không còn cần thiết.
Trong các ngôn ngữ như C, lập trình viên phải tự giải phóng bộ nhớ cho các đối tượng không sử dụng (bộ sưu tập rác của các đối tượng không sử dụng), trong khi bộ sưu tập rác trong Python được tự động chăm sóc bởi chính ngôn ngữ. Python sử dụng hai phương pháp để thu thập rác tự động:
Trước tiên hãy giải thích số lượng tham chiếu là gì, và sau đó chúng ta sẽ tìm hiểu thêm về bộ sưu tập rác trên cơ sở đếm tham chiếu! Số lượng tham chiếuNhư chúng ta đã thấy trước đó, CPython nội bộ tạo ra các thuộc tính 4 và 52 cho mỗi đối tượng.Hãy xem xét một ví dụ để hiểu rõ hơn về thuộc tính 52:Khi mã trên được thực thi, CPython sẽ tạo một đối tượng 54 loại 55, như được hiển thị bên dưới:Trường 52 cho biết số lượng tham chiếu đến đối tượng. Chúng ta biết rằng trong Python, các biến chỉ là các tham chiếu đến các đối tượng. Trong ví dụ trên, biến 8 là tham chiếu duy nhất cho đối tượng chuỗi 54. Do đó, giá trị 52 của đối tượng chuỗi 54 là 12.Chúng ta có thể nhận được số lượng tham chiếu của bất kỳ đối tượng nào trong Python bằng phương pháp 62.Chúng ta hãy lấy số lượng tham chiếu của đối tượng chuỗi 54:
Đầu ra của mã trên là 64. Điều này chỉ ra rằng đối tượng chuỗi 54 đang được tham chiếu bởi hai biến. Tuy nhiên, chúng tôi đã thấy trước đó rằng đối tượng 54 chỉ được tham chiếu bởi biến 8.Tại sao giá trị đếm tham chiếu 64 cho đối tượng chuỗi 54 khi sử dụng phương thức 62?Để hiểu điều này, hãy để xem xét định nghĩa của phương pháp 62:
Lưu ý: Định nghĩa 62 ở trên chỉ dành cho mục đích giải thích.Ở đây, khi chúng ta chuyển biến 8 cho phương thức 62, đối tượng 54 cũng được đề cập bởi tham số 76 của phương thức 62. Do đó, số lượng tham chiếu của đối tượng 54 là 64.Do đó, bất cứ khi nào chúng tôi sử dụng phương thức 62 để lấy số lượng tham chiếu của một đối tượng, số lượng tham chiếu sẽ luôn luôn nhiều hơn 1 so với số lượng tham chiếu thực tế của đối tượng.Hãy tạo một biến khác, 0, chỉ vào cùng một đối tượng chuỗi 54:Các biến 8 và 0 đều chỉ vào đối tượng chuỗi 54. Do đó, số lượng tham chiếu của đối tượng chuỗi 54 sẽ là 2 và đầu ra của phương thức 62 sẽ là 3.
Giảm số lượng tham chiếuĐể giảm số lượng tham chiếu, chúng tôi phải xóa các tham chiếu đến biến. Đây là một ví dụ: Biến 0 không còn trỏ đến đối tượng chuỗi 54. Do đó, số lượng tham chiếu của đối tượng chuỗi 54 cũng sẽ giảm.
Giảm số lượng tham chiếu bằng cách sử dụng từ khóa i = 0 while i < 100: i = i + 1 91Chúng tôi cũng có thể sử dụng từ khóa 91 để giảm số lượng tham chiếu của một đối tượng.Nếu chúng ta gán 93 cho biến 0 ( 95), 0 không còn trỏ đến đối tượng chuỗi 54. Từ khóa 91 hoạt động theo cùng một cách và được sử dụng để xóa tham chiếu của đối tượng, do đó giảm số lượng tham chiếu của nó.Xin lưu ý rằng từ khóa 91 không xóa đối tượng.Xem xét ví dụ sau: Ở đây, chúng tôi chỉ đang xóa tham chiếu của 0. Đối tượng chuỗi 54 không bị xóa.Bây giờ chúng ta hãy lấy số lượng tham chiếu của đối tượng chuỗi 54:
Hoàn hảo! Số lượng tham chiếu của 0 bây giờ là 2.Hãy tóm tắt lại những gì chúng ta đã học về số lượng tham chiếu! Số lượng tham chiếu của một đối tượng tăng nếu chúng ta gán cùng một đối tượng cho một biến mới. Khi chúng ta phân định đối tượng bằng cách sử dụng từ khóa 91 hoặc bằng cách làm cho nó trỏ đến 93, số lượng tham chiếu của đối tượng đó sẽ giảm.Bây giờ chúng ta đã hiểu rõ hơn về khái niệm số lượng tham chiếu trong Python, hãy tìm hiểu cách thu gom rác hoạt động trên cơ sở số lượng tham chiếu. Bộ sưu tập rác trên cơ sở số lượng tham chiếuBộ sưu tập rác trên cơ sở số lượng tham chiếu sử dụng số lượng tham chiếu của đối tượng để giải phóng hoặc lấy lại bộ nhớ. Khi số lượng tham chiếu của đối tượng bằng 0, bộ sưu tập rác của Python sẽ vào và loại bỏ đối tượng khỏi bộ nhớ. Khi một đối tượng bị xóa khỏi bộ nhớ, nó có thể kích hoạt việc xóa các đối tượng khác. Xem xét ví dụ sau: 0Ở đây, chúng tôi chỉ đang xóa tham chiếu của 0. Đối tượng chuỗi 54 không bị xóa.Bây giờ chúng ta hãy lấy số lượng tham chiếu của đối tượng chuỗi 54:Hoàn hảo! Số lượng tham chiếu của 0 bây giờ là 2.Hãy tóm tắt lại những gì chúng ta đã học về số lượng tham chiếu! Số lượng tham chiếu của một đối tượng tăng nếu chúng ta gán cùng một đối tượng cho một biến mới. Khi chúng ta phân định đối tượng bằng cách sử dụng từ khóa 91 hoặc bằng cách làm cho nó trỏ đến 93, số lượng tham chiếu của đối tượng đó sẽ giảm.Bây giờ chúng ta đã hiểu rõ hơn về khái niệm số lượng tham chiếu trong Python, hãy tìm hiểu cách thu gom rác hoạt động trên cơ sở số lượng tham chiếu. Bộ sưu tập rác trên cơ sở số lượng tham chiếu
Bộ sưu tập rác được kích hoạt ngay khi số lượng tham chiếu của đối tượng trở thành 0. Đây là thuật toán thu gom rác chính của Python, và do đó, nó không thể bị vô hiệu hóa. Bộ sưu tập rác trên cơ sở số lượng tham chiếu không hoạt động nếu có tài liệu tham khảo theo chu kỳ. Để miễn phí hoặc đòi lại bộ nhớ của các đối tượng có tài liệu tham khảo theo chu kỳ, Python sử dụng thuật toán thu thập rác thế hệ. Tiếp theo, chúng tôi sẽ thảo luận về các tài liệu tham khảo theo chu kỳ và sau đó đi sâu hơn để hiểu thêm về thuật toán Bộ sưu tập rác thế hệ! Tài liệu tham khảo theo chu kỳ trong PythonMột tham chiếu theo chu kỳ hoặc tham chiếu tròn là một điều kiện trong đó một đối tượng tự tham khảo hoặc khi hai đối tượng khác nhau đề cập đến nhau. Tài liệu tham khảo theo chu kỳ chỉ có thể với các đối tượng container, chẳng hạn như danh sách, dict và đối tượng do người dùng xác định. Không thể với các loại dữ liệu bất biến, chẳng hạn như số nguyên, phao hoặc chuỗi. Xem xét ví dụ sau: 1Như đã thấy trong biểu diễn trên, đối tượng mảng 0 đang tự tham khảo.Hãy xóa tham chiếu 0:Khi chúng tôi xóa tham chiếu 0, đối tượng mảng sẽ không thể truy cập được từ mã Python, nhưng nó sẽ tiếp tục tồn tại trong bộ nhớ, như trong hình trên.Vì đối tượng mảng đang tham chiếu, số lượng tham chiếu của đối tượng mảng sẽ không bao giờ trở thành 0 và nó sẽ không bao giờ được thu thập bởi bộ thu gom rác tham chiếu. Hãy xem xét một ví dụ khác: 2Ở đây, chúng tôi đã xác định hai đối tượng, 25 và 26, của các lớp 27 và 28, tương ứng. 25 được đề cập bởi biến 30 và 26 được đề cập bởi biến 32. 25 có một tài sản 34 chỉ vào 26. Tương tự, đối tượng 26 có thuộc tính 37 chỉ vào 25. 25 và 26 có thể được truy cập trong mã Python với sự trợ giúp của các biến 30 và 32, tương ứng.Hãy xóa các biến 30 và 32Khi chúng ta xóa các biến 30 và 32, 25 và 26 sẽ không thể truy cập được từ cơ sở mã Python, nhưng chúng sẽ tiếp tục tồn tại trong bộ nhớ.Số lượng tham chiếu của các đối tượng này sẽ không bao giờ trở thành 0, vì chúng chỉ vào nhau (theo thuộc tính 37 và 34). Do đó, những đối tượng này sẽ không bao giờ được thu thập bởi bộ thu gom rác tham chiếu.Vì số lượng tham chiếu của các đối tượng có tham chiếu theo chu kỳ không bao giờ trở thành 0, phương thức thu thập rác tham chiếu sẽ không bao giờ làm sạch các đối tượng này. Đối với những trường hợp như vậy, Python cung cấp một thuật toán thu gom rác khác có tên là Bộ sưu tập rác thế hệ. Bộ sưu tập rác thế hệ trong PythonThuật toán thu thập rác thế hệ giải quyết vấn đề thu thập rác đối tượng có tài liệu tham khảo tròn. Vì các tham chiếu tròn chỉ có thể với các đối tượng container, nó quét tất cả các đối tượng container, phát hiện các đối tượng có tham chiếu tròn và loại bỏ chúng nếu chúng có thể được thu thập rác. Để giảm số lượng đối tượng được quét, bộ sưu tập rác thế hệ cũng bỏ qua các bộ dữ liệu chỉ chứa các loại bất biến (ví dụ: int và chuỗi). Vì các đối tượng quét và phát hiện các chu kỳ là một quá trình tốn thời gian, thuật toán thu thập rác thế hệ không phải là thời gian thực. Nó được kích hoạt định kỳ. Khi thuật toán thu gom rác thế hệ được kích hoạt, mọi thứ khác đều bị dừng lại. Do đó, để giảm số lần thu gom rác thế hệ được kích hoạt, CPython phân loại các đối tượng container thành nhiều thế hệ và xác định ngưỡng cho từng thế hệ này. Bộ sưu tập rác thế hệ được kích hoạt nếu số lượng đối tượng trong một thế hệ nhất định vượt quá ngưỡng xác định. CPYThon phân loại các đối tượng thành ba thế hệ (thế hệ 0, 1 và 2). Khi một đối tượng mới được tạo ra, nó thuộc về thế hệ đầu tiên. Nếu đối tượng này không được thu thập khi CPython chạy thuật toán thu gom rác thế hệ, thì nó sẽ chuyển sang thế hệ thứ hai. Nếu đối tượng không được thu thập khi CPython chạy bộ sưu tập rác thế hệ một lần nữa, nó sẽ được chuyển sang thế hệ thứ ba. Đây là thế hệ cuối cùng, và đối tượng sẽ vẫn ở đó. Nói chung, hầu hết các đối tượng được thu thập trong thế hệ đầu tiên. Khi bộ sưu tập rác thế hệ được kích hoạt cho một thế hệ nhất định, nó cũng thu thập tất cả các thế hệ trẻ. Ví dụ: nếu bộ sưu tập rác được kích hoạt cho thế hệ 1, nó cũng sẽ thu thập các đối tượng có trong Thế hệ 0. Tình huống mà cả ba thế hệ (0, 1 và 2) được thu thập rác được gọi là bộ sưu tập đầy đủ. Vì bộ sưu tập 9 liên quan đến việc quét và phát hiện các chu kỳ trong một số lượng lớn các đối tượng, Cpython cố gắng tránh thu thập 9 càng nhiều càng tốt.Chúng ta có thể thay đổi hành vi của người thu gom rác thế hệ bằng mô -đun 0 do Python cung cấp. Bộ sưu tập rác thế hệ có thể được vô hiệu hóa bằng mô -đun 0. Do đó, nó còn được gọi là bộ sưu tập rác tùy chọn.Tiếp theo, chúng tôi sẽ giải thích một số phương pháp quan trọng của mô -đun 0.i = 0 # malloc(i) while i < 100: # malloc(i + 1) # free(i) i = i + 1 0 Mô -đun trong PythonChúng ta có thể sử dụng phương pháp sau để có được ngưỡng được xác định cho mỗi thế hệ: 3Đầu ra trên chỉ ra rằng ngưỡng cho thế hệ đầu tiên là 700, trong khi nó là 10 cho thế hệ thứ hai và thứ ba. Nếu có hơn 700 đối tượng trong thế hệ đầu tiên, bộ sưu tập rác thế hệ sẽ được kích hoạt cho tất cả các đối tượng trong thế hệ đầu tiên. Nếu có hơn 10 đối tượng trong thế hệ thứ 2, bộ sưu tập rác thế hệ sẽ được kích hoạt cho cả hai thế hệ 1 và 0. Chúng ta cũng có thể kiểm tra số lượng đối tượng trong mỗi thế hệ, như được hiển thị bên dưới: 4Ở đây, số lượng đối tượng trong thế hệ đầu tiên là 679, trong khi số lượng đối tượng trong thế hệ thứ hai là 8 và số lượng đối tượng trong thế hệ thứ ba là 0. Chúng ta cũng có thể chạy thuật toán thu thập rác thế hệ theo cách thủ công, như hình dưới đây: 57 sẽ kích hoạt bộ sưu tập rác thế hệ. Theo mặc định, nó chạy một bộ sưu tập đầy đủ. Để chạy bộ sưu tập rác thế hệ cho thế hệ đầu tiên, chúng ta có thể gọi phương pháp này như được hiển thị bên dưới: 5Hãy kiểm tra số lượng đối tượng vẫn còn sống sau quá trình thu thập, 6Chúng tôi cũng có thể cập nhật ngưỡng thế hệ cho từng thế hệ, như được hiển thị bên dưới: 7Chúng ta có thể vô hiệu hóa bộ sưu tập rác thế hệ bằng lệnh sau: Ngược lại, chúng ta có thể bật lại bằng cách sử dụng lệnh sau: Sự kết luậnTrong bài viết này, chúng tôi đã học được rằng Python là một tập hợp các quy tắc và thông số kỹ thuật, và CPython là việc triển khai tham chiếu của Python trong C. Phân bổ và phân bổ mục đích chung, mà Python sử dụng để quản lý bộ nhớ hiệu quả. Sau đó, chúng tôi đã tìm hiểu về các đấu trường, nhóm và các khối mà Trình quản lý bộ nhớ Python sử dụng để tối ưu hóa phân bổ bộ nhớ/phân bổ cho các đối tượng nhỏ (nhỏ hơn hoặc bằng kích thước byte 512 byte) trong một chương trình. Chúng tôi cũng đã tìm hiểu về các thuật toán thu gom rác, chẳng hạn như đếm tham chiếu và thu gom rác thế hệ. Người giới thiệu
Là quản lý bộ nhớ tự động Python?Lập trình viên phải phân bổ thủ công bộ nhớ trước khi chương trình có thể sử dụng và phát hành nó khi chương trình không còn cần nó nữa. Trong Python, quản lý bộ nhớ là tự động! Python tự động xử lý việc phân bổ và giải quyết bộ nhớ.In Python, memory management is automatic! Python automatically handles the allocation and deallocation of memory.
Tại sao Python sử dụng nhiều bộ nhớ như vậy?Những con số đó có thể dễ dàng phù hợp với số nguyên 64 bit, vì vậy người ta sẽ hy vọng Python sẽ lưu trữ hàng triệu số nguyên đó không quá ~ 8MB: một triệu đối tượng 8 byte.Trên thực tế, Python sử dụng nhiều RAM hơn 35 MB để lưu trữ các số này.Tại sao?Bởi vì số nguyên python là đối tượng và các đối tượng có nhiều bộ nhớ trên đầu.Because Python integers are objects, and objects have a lot of memory overhead.
Quản lý bộ nhớ tự động là gì?Quản lý bộ nhớ tự động là một trong những dịch vụ mà thời gian chạy ngôn ngữ chung cung cấp trong quá trình thực hiện được quản lý.Trình thu gom rác của ngôn ngữ chung của ngôn ngữ quản lý việc phân bổ và phát hành bộ nhớ cho một ứng dụng.one of the services that the Common Language Runtime provides during Managed Execution. The Common Language Runtime's garbage collector manages the allocation and release of memory for an application.
Làm thế nào để Python giải phóng bộ nhớ?Như đã giải thích trước đó, Python xóa các đối tượng không còn được tham chiếu trong chương trình để giải phóng không gian bộ nhớ.Quá trình này trong đó Python giải phóng các khối bộ nhớ không còn được sử dụng được gọi là bộ sưu tập rác.deletes objects that are no longer referenced in the program to free up memory space. This process in which Python frees blocks of memory that are no longer used is called Garbage Collection. |