2013-06-04 34 views
6

Một trong các ứng dụng python của tôi dường như bị rò rỉ bộ nhớ, đánh giá việc sử dụng bộ nhớ tăng dần. Giả thuyết của tôi là một tham chiếu tuần hoàn ở đâu đó, bất chấp những nỗ lực tốt nhất để tránh điều này. Để cô lập vấn đề tôi đang tìm cách để kiểm tra thủ công các mục không thể truy cập, một công cụ nhằm mục đích gỡ lỗi hoàn toàn.gặp khó khăn khi tìm hiểu gc.garbage của python (để truy tìm rò rỉ bộ nhớ)

Mô-đun gc có vẻ như có khả năng theo dõi cần thiết và tôi đã thử mã sau nhằm mục đích biên soạn danh sách các mục không thể truy cập được tạo thành từ cuộc gọi cuối cùng. Cuộc gọi đầu tiên chỉ đặt một trạm kiểm soát cơ sở và sẽ không xác định các mục không thể truy cập được.

def unreachable(): 
    # first time setup 
    import gc 
    gc.set_threshold(0) # only manual sweeps 
    gc.set_debug(gc.DEBUG_SAVEALL) # keep unreachable items as garbage 
    gc.enable() # start gc if not yet running (is this necessary?) 
    # operation 
    if gc.collect() == 0: 
    return 'no unreachable items' 
    s = 'unreachable items:\n ' \ 
    + '\n '.join('[%d] %s' % item for item in enumerate(gc.garbage)) 
    _deep_purge_list(gc.garbage) # remove unreachable items 
    return s # return unreachable items as text 

nhằm phá vỡ chu kỳ và xóa đối tượng theo cách thủ công. Việc thực hiện sau xử lý một số trường hợp phổ biến nhưng không gần chặt nước. Câu hỏi đầu tiên của tôi liên quan đến điều này, xem xuống.

def _deep_purge_list(garbage): 
    for item in garbage: 
    if isinstance(item, dict): 
     item.clear() 
    if isinstance(item, list): 
     del item[:] 
    try: 
     item.__dict__.clear() 
    except: 
     pass 
    del garbage[:] 

Dựa trên thử nghiệm rất hạn chế, thiết lập có vẻ hoạt động đúng. Các tài liệu tham khảo theo chu kỳ sau báo cáo một cách chính xác một lần:

class A(object): 
    def __init__(self): 
    self.ref = self 

print unreachable() 
# no unreachable items 

A() 

print unreachable() 
# unreachable items: 
# [0] <__main__.A object at 0xb74579ac> 
# [1] {'ref': <__main__.A object at 0xb74579ac>} 

print unreachable() 
# no unreachable items 

Tuy nhiên với một cái gì đó sau lẻ xảy ra:

print unreachable() 
# no unreachable items 

import numpy 

print unreachable() 
# unreachable items: 
# [0] (<type '_ctypes.Array'>,) 
# [1] {'__module__': 'numpy.ctypeslib', '__dict__': <attribute '__dict__' of 'c_long_Array_1' objects>, '__weakref__': <attribute '__weakref__' of 'c_long_Array_1' objects>, '_length_': 1, '_type_': <class 'ctypes.c_long'>, '__doc__': None} 
# [2] <class 'numpy.ctypeslib.c_long_Array_1'> 
# [3] <attribute '__dict__' of 'c_long_Array_1' objects> 
# [4] <attribute '__weakref__' of 'c_long_Array_1' objects> 
# [5] (<class 'numpy.ctypeslib.c_long_Array_1'>, <type '_ctypes.Array'>, <type '_ctypes._CData'>, <type 'object'>) 

print unreachable() 
# unreachable items: 
# [0] (<type '_ctypes.Array'>,) 
# [1] {} 
# [2] <class 'c_long_Array_1'> 
# [3] (<class 'c_long_Array_1'>, <type '_ctypes.Array'>, <type '_ctypes._CData'>, <type 'object'>) 

lời gọi nhiều lần vẫn tiếp tục quay mà kết quả cuối cùng. Vấn đề không xảy ra khi không thể truy cập được lần đầu tiên sau khi nhập. Tuy nhiên, tại thời điểm này tôi không có lý do gì để tin rằng vấn đề này có tính chất cụ thể; tôi đoán là nó phơi bày một lỗ hổng trong cách tiếp cận của tôi.

Câu hỏi của tôi:

  1. Có cách nào tốt hơn để loại bỏ các mục trong gc.garbage? Lý tưởng nhất, là có một cách để có gc loại bỏ chúng, như nó sẽ (nên?) Đã thực hiện mà không DEBUG_SAVEALL?
  2. Ai đó có thể giải thích vấn đề với việc nhập khẩu khó khăn và/hoặc đề xuất các cách khắc phục sự cố không?

suy nghĩ:

Dường như mã dưới đây biểu diễn gần dự định:

def unreachable(): 
    import gc 
    gc.set_threshold(0) 
    gc.set_debug(gc.DEBUG_LEAK) 
    gc.enable() 
    print 'collecting {{{' 
    gc.collect() 
    print '}}} done' 

Tuy nhiên, để gỡ lỗi Tôi thích biểu diễn chuỗi phong phú hơn loại/id theo quy định của gc. Hơn nữa tôi muốn hiểu sai sót trong cách tiếp cận cũ của tôi, và tìm hiểu điều gì đó về mô-đun gc.

trân trọng sự giúp đỡ của bạn,

Gertjan

Cập nhật 05/06:

tôi chạy vào một tình huống mà việc thực hiện đầu tiên đã không báo cáo bất kỳ mặt hàng không thể truy cập, trừ khi người dân địa phương() được gọi ngay trước khi cho nó (loại bỏ giá trị trả lại). Không hiểu làm thế nào điều này có thể ảnh hưởng đến việc theo dõi đối tượng của gc, điều này khiến tôi bối rối hơn. Tôi không chắc chắn sẽ dễ dàng như thế nào để xây dựng một ví dụ nhỏ thể hiện vấn đề này, nhưng nếu nhu cầu đòi hỏi nó tôi có thể cho nó một shot.

+0

Tôi chỉ đọc lướt qua, nhưng bạn có thể đã hiểu nhầm 'gc.DEBUG_SAVEALL': nó có nghĩa là gắn thêm các đối tượng được giải phóng vào' gc.garbage' (thay vì chỉ giải phóng chúng). – blueyed

Trả lời

0

Lần cuối cùng tôi có nhu cầu như vậy tôi đã kết thúc bằng cách sử dụng objgraph module để có hiệu quả tốt. Nó cung cấp thông tin chính xác hơn nhiều so với bạn có thể dễ dàng lấy trực tiếp từ số gc module. Thật không may tôi không có bất kỳ mã nào trong tay minh họa cách sử dụng nó.

Một nơi mà nó rơi xuống nằm trong bộ nhớ được phân bổ bởi bất kỳ thư viện mã C nào được gọi. Ví dụ, nếu một dự án sử dụng PIL, nó rất dễ bị rò rỉ bộ nhớ do không giải phóng các đối tượng python đúng cách được hỗ trợ bởi dữ liệu C. Đó là mô-đun được hỗ trợ C phụ thuộc vào cách đóng đúng các đối tượng như vậy.

+0

Hi Samantha, cảm ơn, vâng tôi đồng ý objgraph là một công cụ tuyệt vời để truy tìm tài liệu tham khảo đối tượng. Tuy nhiên, tôi không thể tìm ra cách sử dụng nó để cung cấp cho tôi một danh sách các mục không thể truy cập, theo cách mà 'A' xuất hiện trong ví dụ của tôi; thử nghiệm với get_leaking_objects không thành công. Trong bài đăng trên blog của mình, Marius giải thích rò rỉ bộ nhớ bằng ví dụ về các tham chiếu từ các đối tượng toàn cầu, vì vậy tôi đã tin rằng objgraph có thể không phù hợp để truy tìm các tham chiếu tuần hoàn. Nếu kết luận đó là sai, tôi quan tâm nhất để tìm hiểu làm thế nào chúng có thể được phát hiện. – gertjan

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