2010-04-05 33 views
6

Tôi đang cố gắng hiểu nội bộ của bộ thu gom CPython, đặc biệt khi trình phá hủy được gọi. Cho đến nay, hành vi này là trực quan, nhưng trường hợp sau đây cho tôi biết:Tại sao bộ hủy được gọi khi bộ thu gom CPython bị tắt?

  1. Tắt GC.
  2. Tạo đối tượng, sau đó xóa tham chiếu đến đối tượng đó.
  3. Đối tượng bị hủy và phương thức _____del_____ được gọi.

Tôi nghĩ điều này sẽ chỉ xảy ra nếu bộ thu gom rác được bật. Ai đó có thể giải thích tại sao điều này xảy ra? Có cách nào trì hoãn việc gọi điện cho destructor không?

import gc 
import unittest 

_destroyed = False 

class MyClass(object): 

    def __del__(self): 
     global _destroyed 
     _destroyed = True 

class GarbageCollectionTest(unittest.TestCase): 

    def testExplicitGarbageCollection(self): 
     gc.disable() 
     ref = MyClass() 
     ref = None 
     # The next test fails. 
     # The object is automatically destroyed even with the collector turned off. 
     self.assertFalse(_destroyed) 
     gc.collect() 
     self.assertTrue(_destroyed) 

if __name__=='__main__': 
    unittest.main() 

Disclaimer: mã này không có nghĩa là phục vụ sản xuất - Tôi đã lưu ý rằng đây là rất thực hiện cụ thể và không hoạt động trên Jython.

Trả lời

9

Python có cả tham khảo đếm thu gom rác thải và cyclic thu gom rác thải, và đó là thứ hai rằng gc điều khiển mô-đun. Không thể tắt tính năng tham chiếu và do đó sẽ vẫn xảy ra khi bộ thu gom rác tuần hoàn tắt.

Vì không có tham chiếu nào còn lại đối tượng của bạn sau ref = None, phương thức __del__ được gọi là kết quả của số tham chiếu của nó sẽ bằng không.

Có một đầu mối trong the documentation: "Vì bộ sưu tập bổ sung tính tham chiếu đã được sử dụng trong Python ..." (nhấn mạnh của tôi).

Bạn có thể ngừng khẳng định đầu tiên từ bắn bằng cách làm cho đối tượng đề cập đến bản thân, do đó số lượng tài liệu tham khảo của nó không đi đến số không, ví dụ bằng cách cho nó constructor này:

def __init__(self): 
    self.myself = self 

Nhưng nếu bạn làm điều đó, xác nhận thứ hai sẽ cháy. Đó là vì các chu kỳ rác với các phương thức __del__ không được thu thập - xem tài liệu cho gc.garbage.

4

Tùy thuộc vào định nghĩa của bạn về bộ thu gom rác, CPython có hai bộ thu gom rác, tham chiếu đếm một và bộ lọc còn lại.
Bộ đếm tham chiếu luôn hoạt động và không thể tắt, vì nó khá nhanh và nhẹ không ảnh hưởng đến thời gian chạy của hệ thống.
Loại khác (một số dấu hiệu và quét, tôi nghĩ), được chạy thường xuyên và có thể bị vô hiệu hóa. Điều này là do nó yêu cầu thông dịch viên bị tạm dừng trong khi nó đang chạy, và điều này có thể xảy ra tại thời điểm sai, và tiêu thụ khá nhiều thời gian CPU.
Khả năng vô hiệu hóa tính năng này có sẵn cho những thời điểm bạn dự định làm điều gì đó quan trọng và việc thiếu GC này sẽ không gây ra bất kỳ sự cố nào cho bạn.

+0

Đây có phải là "hai người thu gom rác thải" được thực hiện ở đâu đó không? – Frederik

+0

Hãy xem câu trả lời của Alex Martelli và các liên kết liên quan của Alex Martelli. Nó có lẽ tốt hơn bất cứ thứ gì khác tôi có thể nghĩ ra. –

4

Tài liệu here giải thích cách gọi là "bộ thu gom rác tùy chọn" thực sự là bộ sưu tập của cyclic rác (loại tính tham chiếu sẽ không bắt được).tính tham khảo được giải thích here, với một cái gật đầu để động lẫn nhau của nó với gc cyclic:

Trong khi Python sử dụng tài liệu tham khảo thực hiện đếm truyền thống, nó cũng cung cấp một máy dò chu kỳ đó hoạt động để phát hiện chu kỳ tài liệu tham khảo. Điều này cho phép các ứng dụng không lo lắng về việc tạo tham chiếu trực tiếp hoặc gián tiếp ; đây là điểm yếu của bộ sưu tập rác được triển khai bằng cách sử dụng tính năng chỉ tham chiếu . Tham chiếu chu kỳ bao gồm các đối tượng mà chứa tham chiếu (có thể gián tiếp) cho chính chúng, sao cho mỗi đối tượng trong chu trình có số tham chiếu là khác không. Điển hình tham khảo triển khai đếm không thể để đòi lại bộ nhớ thuộc bất kỳ đối tượng trong một chu kỳ tài liệu tham khảo, hoặc tham chiếu từ các đối tượng trong chu kỳ , mặc dù không có nguồn tham khảo trong chu kỳ riêng của mình.

Các vấn đề liên quan