Vòng đời của đối tượng¶
Phần này giải thích cách các vị trí của một loại liên quan với nhau trong suốt vòng đời của một đối tượng. Nó không nhằm mục đích trở thành một tài liệu tham khảo chuẩn hoàn chỉnh cho các vị trí; thay vào đó, hãy tham khảo tài liệu dành riêng cho vị trí trong Kiểu cấu trúc đối tượng để biết chi tiết về một vị trí cụ thể.
Sự kiện cuộc sống¶
Hình dưới đây minh họa thứ tự các sự kiện có thể xảy ra trong suốt vòng đời của một đối tượng. Một mũi tên từ A đến B cho biết rằng sự kiện B có thể xảy ra sau khi sự kiện A xảy ra, với nhãn của mũi tên cho biết điều kiện phải đúng để B xảy ra sau A.
Giải thích:
Khi một đối tượng mới được xây dựng bằng cách gọi kiểu của nó:
tp_newđược gọi để tạo một đối tượng mới.tp_allocđượctp_newgọi trực tiếp để cấp phát bộ nhớ cho đối tượng mới.tp_initkhởi tạo đối tượng mới được tạo.tp_initcó thể được gọi lại để khởi tạo lại một đối tượng nếu muốn. Lệnh gọitp_initcũng có thể được bỏ qua hoàn toàn, chẳng hạn như bằng mã Python gọi__new__().
Sau khi
tp_inithoàn thành, đối tượng đã sẵn sàng để sử dụng.Một thời gian sau khi tham chiếu cuối cùng đến một đối tượng bị xóa:
Nếu một đối tượng không được đánh dấu là finalized, nó có thể được hoàn thiện bằng cách đánh dấu nó là finalized và gọi hàm
tp_finalizecủa nó. Python thực hiện not hoàn thiện một đối tượng khi tham chiếu cuối cùng đến nó bị xóa; sử dụngPyObject_CallFinalizerFromDealloc()để đảm bảo rằngtp_finalizeluôn được gọi.Nếu đối tượng được đánh dấu là đã hoàn thiện,
tp_clearcó thể được bộ thu gom rác gọi để xóa các tham chiếu do đối tượng nắm giữ. Nó được gọi là not khi số tham chiếu của đối tượng đạt tới 0.tp_deallocđược gọi để tiêu diệt đối tượng. Để tránh trùng lặp mã,tp_deallocthường gọitp_clearđể giải phóng các tham chiếu của đối tượng.Khi
tp_deallochoàn thành việc hủy đối tượng, nó sẽ gọi trực tiếptp_free(thường được đặt thànhPyObject_Free()hoặcPyObject_GC_Del()tự động tùy theo loại) để phân bổ bộ nhớ.
Hàm
tp_finalizeđược phép thêm tham chiếu đến đối tượng nếu muốn. Nếu có, đối tượng là resurrected, ngăn chặn sự hủy diệt đang chờ xử lý của nó. (Chỉtp_finalizemới được phép hồi sinh một đối tượng;tp_clearvàtp_deallockhông thể không gọi vàotp_finalize.) Việc phục hồi một đối tượng có thể khiến dấu finalized của đối tượng bị xóa hoặc không. Hiện tại, Python không xóa dấu finalized khỏi đối tượng được phục hồi nếu nó hỗ trợ thu gom rác (tức là cờPy_TPFLAGS_HAVE_GCđược đặt) nhưng sẽ xóa dấu nếu đối tượng không hỗ trợ thu gom rác; một hoặc cả hai hành vi này có thể thay đổi trong tương lai.tp_dealloccó thể tùy chọn gọitp_finalizethông quaPyObject_CallFinalizerFromDealloc()nếu nó muốn sử dụng lại mã đó để giúp phá hủy đối tượng. Điều này được khuyến khích vì nó đảm bảo rằngtp_finalizeluôn được gọi trước khi hủy. Xem tài liệutp_deallocđể biết mã ví dụ.Nếu đối tượng là thành viên của cyclic isolate và
tp_clearkhông phá vỡ được chu trình tham chiếu hoặc không phát hiện được cách ly tuần hoàn (có thểgc.disable()đã được gọi hoặc cờPy_TPFLAGS_HAVE_GCbị bỏ sót do nhầm lẫn trong một trong các loại liên quan), thì các đối tượng vẫn không thể thu thập được vô thời hạn (chúng bị "rò rỉ"). Xemgc.garbage.
Nếu đối tượng được đánh dấu là hỗ trợ thu gom rác (cờ Py_TPFLAGS_HAVE_GC được đặt trong tp_flags), các sự kiện sau cũng có thể xảy ra:
Trình thu gom rác thỉnh thoảng gọi
tp_traverseđể xác định cyclic isolates.Khi trình thu gom rác phát hiện ra một cyclic isolate, nó sẽ hoàn thiện một trong các đối tượng trong nhóm bằng cách đánh dấu nó là finalized và gọi hàm
tp_finalizecủa nó, nếu có. Điều này lặp lại cho đến khi sự cô lập theo chu kỳ không tồn tại hoặc tất cả các đối tượng đã được hoàn thiện.tp_finalizeđược phép phục hồi đối tượng bằng cách thêm một tham chiếu từ bên ngoài cyclic isolate. Tham chiếu mới làm cho nhóm đối tượng không còn tạo thành vòng cô lập tuần hoàn nữa (chu trình tham chiếu có thể vẫn tồn tại, nhưng nếu có thì các đối tượng không còn bị cô lập nữa).Khi trình thu gom rác phát hiện ra một cyclic isolate và tất cả các đối tượng trong nhóm đã được đánh dấu là finalized, trình thu gom rác sẽ xóa một hoặc nhiều đối tượng không rõ ràng trong nhóm (có thể đồng thời) bằng cách gọi hàm
tp_clearcủa từng đối tượng. Điều này lặp lại miễn là vòng cách ly vẫn tồn tại và không phải tất cả các đối tượng đều bị xóa.
Phá hủy cô lập theo chu kỳ¶
Dưới đây là các giai đoạn tồn tại của một cyclic isolate giả định tiếp tục tồn tại sau khi mỗi đối tượng thành viên được hoàn thiện hoặc xóa. Đó là rò rỉ bộ nhớ nếu quá trình cô lập theo chu kỳ tiến triển qua tất cả các giai đoạn này; nó sẽ biến mất sau khi tất cả các đối tượng được dọn sạch, nếu không sớm hơn. Sự cô lập theo chu kỳ có thể biến mất do chu trình tham chiếu bị hỏng hoặc do các đối tượng không còn bị cô lập do sự phục hồi của bộ hoàn thiện (xem tp_finalize).
Reachable (chưa phải là cách ly theo chu kỳ): Tất cả các đối tượng đều ở trạng thái bình thường, có thể truy cập được. Một chu trình tham chiếu có thể tồn tại, nhưng một tham chiếu bên ngoài có nghĩa là các đối tượng chưa bị cô lập.
Unreachable but consistent: Tham chiếu cuối cùng từ bên ngoài nhóm đối tượng tuần hoàn đã bị xóa, khiến các đối tượng bị cô lập (do đó sự cô lập tuần hoàn được sinh ra). Chưa có đối tượng nào của nhóm được hoàn thiện hoặc xóa. Quá trình cô lập theo chu kỳ vẫn ở giai đoạn này cho đến khi một số lần chạy trình thu gom rác trong tương lai (không nhất thiết là lần chạy tiếp theo vì lần chạy tiếp theo có thể không quét mọi đối tượng).
Mix of finalized and not finalized: Các đối tượng trong cách ly tuần hoàn được hoàn thiện lần lượt, điều đó có nghĩa là có một khoảng thời gian khi cách ly tuần hoàn bao gồm sự kết hợp của các đối tượng đã hoàn thiện và không hoàn thiện. Thứ tự hoàn thiện không được chỉ định nên nó có thể xuất hiện ngẫu nhiên. Một đối tượng đã hoàn thiện phải hoạt động một cách lành mạnh khi các đối tượng chưa hoàn thiện tương tác với nó và một đối tượng chưa hoàn thiện phải có khả năng chấp nhận việc hoàn thiện một tập hợp con tùy ý của các tham chiếu của nó.
All finalized: Tất cả các đối tượng trong vòng cách ly tuần hoàn đều được hoàn thiện trước khi bất kỳ đối tượng nào trong số chúng bị xóa.
Mix of finalized and cleared: Các đối tượng có thể được xóa tuần tự hoặc đồng thời (nhưng với GIL được giữ); Dù thế nào đi nữa, một số sẽ hoàn thành trước những người khác. Một đối tượng cuối cùng phải có khả năng chấp nhận việc xóa một tập hợp con các tham chiếu của nó. PEP 442 gọi giai đoạn này là "thùng rác tuần hoàn".
Leaked: Nếu vẫn tồn tại sự cô lập theo chu kỳ sau khi tất cả các đối tượng trong nhóm đã được hoàn tất và xóa, thì các đối tượng đó vẫn không thể thu thập được vô thời hạn (xem
gc.garbage). Sẽ là một lỗi nếu quá trình cách ly theo chu kỳ đạt đến giai đoạn này---điều đó có nghĩa là các phương thứctp_clearcủa các đối tượng tham gia đã không thể phá vỡ chu trình tham chiếu theo yêu cầu.
Nếu tp_clear không tồn tại thì Python sẽ không có cách nào để phá vỡ chu trình tham chiếu một cách an toàn. Việc chỉ cần phá hủy một đối tượng theo chu kỳ cô lập sẽ dẫn đến một con trỏ lơ lửng, kích hoạt hành vi không xác định khi một đối tượng tham chiếu đến đối tượng bị phá hủy cũng bị phá hủy. Bước xóa làm cho việc hủy đối tượng trở thành một quá trình gồm hai giai đoạn: đầu tiên tp_clear được gọi để phá hủy một phần các đối tượng đủ để tách chúng ra khỏi nhau, sau đó tp_dealloc được gọi để hoàn thành việc phá hủy.
Không giống như thanh toán bù trừ, quyết toán không phải là một giai đoạn hủy diệt. Một đối tượng đã hoàn thiện vẫn phải hoạt động bình thường bằng cách tiếp tục thực hiện các hợp đồng thiết kế của nó. Trình hoàn thiện của một đối tượng được phép thực thi mã Python tùy ý và thậm chí còn được phép ngăn chặn sự phá hủy sắp xảy ra bằng cách thêm một tham chiếu. Trình hoàn thiện chỉ liên quan đến việc hủy theo lệnh gọi---nếu nó chạy, nó sẽ chạy trước khi hủy, bắt đầu bằng tp_clear (nếu được gọi) và kết thúc bằng tp_dealloc.
Bước hoàn thiện là không cần thiết để lấy lại các đối tượng một cách an toàn theo chu kỳ cô lập, nhưng sự tồn tại của nó giúp thiết kế các loại hoạt động theo cách lành mạnh dễ dàng hơn khi các đối tượng bị xóa. Việc xóa một đối tượng nhất thiết có thể khiến nó ở trạng thái bị hỏng, bị phá hủy một phần---có thể không an toàn khi gọi bất kỳ phương thức nào của đối tượng đã xóa hoặc truy cập bất kỳ thuộc tính nào của nó. Với việc hoàn thiện, chỉ các đối tượng đã hoàn thiện mới có thể tương tác với các đối tượng đã xóa; các đối tượng chưa hoàn thiện được đảm bảo chỉ tương tác với các đối tượng chưa bị xóa (nhưng có khả năng đã hoàn thiện).
Tóm tắt các tương tác có thể xảy ra:
Một đối tượng chưa hoàn thiện có thể có các tham chiếu đến hoặc từ các đối tượng chưa hoàn thiện và đã hoàn thiện, nhưng không đến hoặc từ các đối tượng đã xóa.
Một đối tượng đã hoàn thiện có thể có các tham chiếu đến hoặc từ các đối tượng chưa hoàn thiện, đã hoàn thiện và đã xóa.
Một đối tượng đã xóa có thể có các tham chiếu đến hoặc từ các đối tượng đã hoàn thiện và đã xóa, nhưng không có tham chiếu đến hoặc từ các đối tượng chưa hoàn thiện.
Nếu không có bất kỳ chu trình tham chiếu nào, một đối tượng có thể bị hủy một cách đơn giản sau khi tham chiếu cuối cùng của nó bị xóa; các bước hoàn thiện và xóa là không cần thiết để lấy lại các đối tượng không sử dụng một cách an toàn. Tuy nhiên, dù sao đi nữa, việc tự động gọi tp_finalize và tp_clear trước khi hủy cũng có thể hữu ích vì thiết kế kiểu được đơn giản hóa khi tất cả các đối tượng luôn trải qua cùng một chuỗi sự kiện bất kể chúng có tham gia vào quá trình cô lập theo chu kỳ hay không. Python hiện chỉ gọi tp_finalize và tp_clear khi cần thiết để phá hủy sự cô lập theo chu kỳ; điều này có thể thay đổi trong phiên bản tương lai.
Chức năng¶
Để phân bổ và giải phóng bộ nhớ, hãy xem Cấp phát các đối tượng trên Heap.
-
void PyObject_CallFinalizer(PyObject *op)¶
Hoàn thiện đối tượng như được mô tả trong
tp_finalize. Gọi hàm này (hoặcPyObject_CallFinalizerFromDealloc()) thay vì gọi trực tiếptp_finalizevì hàm này có thể loại bỏ nhiều lệnh gọi đếntp_finalize. Hiện tại, các cuộc gọi chỉ được loại bỏ trùng lặp nếu loại hỗ trợ thu gom rác (tức là cờPy_TPFLAGS_HAVE_GCđược đặt); điều này có thể thay đổi trong tương lai.Added in version 3.4.
-
int PyObject_CallFinalizerFromDealloc(PyObject *op)¶
Tương tự như
PyObject_CallFinalizer()nhưng được gọi ở đầu hàm hủy của đối tượng (tp_dealloc). Không được có bất kỳ tham chiếu nào đến đối tượng. Nếu bộ hoàn thiện của đối tượng phục hồi đối tượng, hàm này trả về -1; không có sự phá hủy nào nữa sẽ xảy ra. Nếu không, hàm này trả về 0 và quá trình hủy có thể tiếp tục bình thường.Added in version 3.4.
Xem thêm
tp_dealloccho mã ví dụ.