2014-04-20 17 views
10

Mã python của tôi đã bị lỗi với lỗi 'Đối tượng GC đã được Theo dõi'. Đang cố gắng tìm ra cách tiếp cận tốt nhất để gỡ lỗi sự cố này.Gỡ lỗi Python Lỗi nghiêm trọng: Đối tượng GC đã được Theo dõi

Hệ điều hành: Linux.

  • Có cách nào thích hợp để gỡ lỗi vấn đề này không.

Có một vài đề xuất trong bài viết sau. Python memory debugging with GDB

Không chắc chắn cách tiếp cận nào phù hợp với tác giả.

  • Có cách nào để tạo bãi chứa bộ nhớ trong trường hợp như vậy có thể được phân tích hay không. Giống như trong thế giới Windows.

Tìm thấy một số bài viết về điều này. Nhưng không hoàn toàn trả lời câu hỏi của tôi: http://pfigue.github.io/blog/2012/12/28/where-is-my-core-dump-archlinux/

+1

Có, bạn có thể tạo một bãi chứa. Trên thực tế, kết xuất được tạo tự động khi có sự cố (segfault) như được mô tả trong bài viết mà bạn đã đề cập đến. Nhưng bạn có thể ép buộc hoạt động bằng tay, bằng cách gửi tín hiệu quá trình bằng cách sử dụng 'kill'. BTW Bạn đã xem http://pyrit.wordpress.com/2010/02/18/385/ chưa? – user3159253

+0

Khi chúng tôi đang thiết lập cho kết xuất lõi, bạn có biết tệp kết xuất được tạo khi quá trình này bị trục trặc và biến mất không? – Feru

+0

Bãi chứa được lưu trữ trong thư mục làm việc hiện tại của một quá trình. – user3159253

Trả lời

3

Vấn đề là bạn cố gắng thêm đối tượng vào theo dõi thu thập rác cyclic theo chu kỳ hai lần.

Check-out this bug, cụ thể:

câu chuyện dài ngắn: nếu bạn thiết lập Py_TPFLAGS_HAVE_GC và bạn đang sử dụng built- Python trong cấp phát bộ nhớ (tiêu chuẩn tp_alloc/tp_free), bạn không bao giờ phải gọi theo cách thủ công PyObject_GC_Track() hoặc PyObject_GC_UnTrack(). Python xử lý tất cả sau lưng của bạn.

Thật không may, điều này không được ghi lại rất tốt, tại thời điểm này. Khi bạn đã khắc phục được sự cố, vui lòng bỏ qua báo cáo lỗi (được liên kết ở trên) về tài liệu hướng dẫn tốt hơn về hành vi này.

+0

Cảm ơn thông tin này Chris. Tôi sẽ xem xét điều này và điền vào các kết quả. – Feru

8

Tìm hiểu lý do cho sự cố này trong trường hợp của tôi (không nhất thiết là lý do duy nhất cho sự cố đối tượng GC). Tôi đã sử dụng các khối GDB và lõi để gỡ lỗi vấn đề này.

Tôi có Mã mở rộng Python và C (trong đối tượng được chia sẻ). Mã Python đăng ký thói quen gọi lại với mã C Extension. Trong một quy trình làm việc nhất định, một luồng từ mã C Extension đã gọi đến thủ tục gọi lại đã đăng ký trong mã Python.

Điều này thường hoạt động tốt nhưng khi nhiều chủ đề đã thực hiện cùng một hành động đồng thời nó dẫn đến sự cố với 'Đối tượng GC đã được theo dõi'.

Đồng bộ hóa quyền truy cập vào các đối tượng python cho nhiều chuỗi không giải quyết được vấn đề này.

Nhờ có bất kỳ phản hồi nào về điều này.

+1

Làm cách nào để bạn đồng bộ hóa quyền truy cập trong ngữ cảnh này? –

2

Tôi đã gặp sự cố này bằng cách sử dụng boost :: python khi mã C++ của chúng tôi kích hoạt gọi lại python.Tôi thỉnh thoảng sẽ nhận được "đối tượng GC đã được theo dõi" và chương trình sẽ chấm dứt.

Tôi đã có thể đính kèm GDB vào quy trình trước khi kích hoạt lỗi. Một điều thú vị, trong mã python, chúng tôi đã gói lại gọi lại với một phần functools, đã thực sự che giấu nơi xảy ra lỗi thực sự. Sau khi thay thế một phần bằng một lớp trình bao bọc có thể gọi đơn giản. "Đối tượng GC đã được theo dõi lỗi" không còn xuất hiện nữa, thay vào đó tôi bây giờ chỉ nhận được một segfault.

Trong tăng của chúng tôi :: trình bao python, chúng tôi đã có hàm lambda để xử lý cuộc gọi lại C++ và hàm lambda đã bắt hàm tăng :: python :: object callback. Hóa ra, vì lý do gì đó, trong destructor cho lambda, nó không phải lúc nào cũng có được GIL khi phá hủy boost :: python :: object đã gây ra segfault.

Khắc phục là không sử dụng hàm lambda, mà thay vào đó hãy tạo một hàm functor để đảm bảo có được GIL trong trình hủy trước khi gọi PyDECREF() trên đối tượng boost :: python ::.

class callback_wrapper 
{ 
public: 
    callback_wrapper(object cb): _cb(cb), _destroyed(false) { 
    } 

    callback_wrapper(const callback_wrapper& other) { 
     _destroyed = other._destroyed; 
     Py_INCREF(other._cb.ptr()); 
     _cb = other._cb; 
    } 

    ~callback_wrapper() { 
     std::lock_guard<std::recursive_mutex> guard(_mutex); 
     PyGILState_STATE state = PyGILState_Ensure(); 
     Py_DECREF(_cb.ptr()); 
     PyGILState_Release(state); 
     _destroyed = true; 
    } 

    void operator()(topic_ptr topic) { 
     std::lock_guard<std::recursive_mutex> guard(_mutex); 
     if(_destroyed) { 
      return; 
     } 
     PyGILState_STATE state = PyGILState_Ensure(); 
     try { 
      _cb(topic); 
     } 
     catch(error_already_set) { PyErr_Print(); } 
     PyGILState_Release(state); 
    } 

    object _cb; 
    std::recursive_mutex _mutex; 
    bool _destroyed; 
}; 
Các vấn đề liên quan