2009-09-16 65 views
112

Tôi có một tập lệnh chạy dài, nếu để chạy đủ lâu, sẽ tiêu thụ tất cả bộ nhớ trên hệ thống của tôi.rò rỉ bộ nhớ Python

Mà không đi vào chi tiết về kịch bản, tôi có hai câu hỏi:

  1. Có bất kỳ "Thực tiễn tốt nhất" để làm theo, mà sẽ giúp ngăn chặn rò rỉ xảy ra?
  2. Có những kỹ thuật nào để gỡ lỗi rò rỉ bộ nhớ trong Python?
+3

Tôi đã tìm thấy [công thức này] (http://code.activestate.com/recipes/65333/) hữu ích. –

+0

Dường như in ra quá nhiều dữ liệu để hữu ích – Casebash

+1

@Casebash: Nếu chức năng đó in bất cứ điều gì bạn nghiêm túc làm sai. Nó liệt kê các đối tượng với phương thức '__del__' không còn được tham chiếu trừ chu kỳ của chúng. Chu kỳ không thể bị hỏng, vì các vấn đề với '__del__'. Sửa nó! –

Trả lời

4

Không chắc chắn về "Thực tiễn tốt nhất" cho rò rỉ bộ nhớ trong python, nhưng python nên xóa bộ nhớ của chính nó bằng bộ thu gom rác. Vì vậy, chủ yếu là tôi sẽ bắt đầu bằng cách kiểm tra danh sách vòng tròn của một số ngắn, vì họ sẽ không được chọn bởi các nhà sưu tập rác.

+3

hoặc tham chiếu đến các đối tượng đang được giữ mãi mãi, vv –

+0

Các bạn có thể cung cấp các ví dụ về danh sách tròn và các đối tượng đang được lưu giữ mãi mãi không? – Daniel

8

Bạn nên đặc biệt xem xét dữ liệu toàn cầu hoặc dữ liệu tĩnh của mình (dữ liệu sống lâu).

Khi dữ liệu này phát triển không hạn chế, bạn cũng có thể gặp khó khăn trong Python.

Bộ thu gom rác chỉ có thể thu thập dữ liệu, không được tham chiếu nữa. Nhưng dữ liệu tĩnh của bạn có thể kết nối các phần tử dữ liệu cần được giải phóng.

Một vấn đề khác có thể là chu trình bộ nhớ, nhưng ít nhất theo lý thuyết, bộ thu gom rác nên tìm và loại bỏ chu trình - ít nhất là chúng không được nối vào một số dữ liệu sống dài.

Loại dữ liệu sống dài nào đặc biệt rắc rối? Có một cái nhìn tốt về bất kỳ danh sách và từ điển - họ có thể phát triển mà không có bất kỳ giới hạn. Trong từ điển bạn thậm chí có thể không thấy sự cố đến từ khi bạn truy cập vào dicts, số lượng các khóa trong từ điển có thể không có tầm nhìn lớn đối với bạn ...

3

Đây không phải là lời khuyên đầy đủ. Nhưng một điều cần lưu ý khi viết với ý nghĩ tránh rò rỉ bộ nhớ trong tương lai (vòng lặp) là đảm bảo rằng bất kỳ thứ gì chấp nhận tham chiếu đến cuộc gọi lại, nên lưu trữ cuộc gọi đó làm tham chiếu yếu.

13

Hãy để tôi giới thiệu công cụ mem_top,
đã giúp tôi giải quyết vấn đề tương tự.

Nó ngay lập tức hiển thị các nghi phạm hàng đầu về rò rỉ bộ nhớ trong chương trình Python.

+0

đó là sự thật ... nhưng nó cho rất ít trong cách sử dụng/giải thích kết quả –

+0

@me_, công cụ này có cả phần "Sử dụng" và "Giải thích kết quả" được ghi lại. Tôi có nên thêm giải thích như "refs là số tài liệu tham khảo từ đối tượng, kiểu là số đối tượng thuộc loại này, byte là kích thước của đối tượng" - liệu nó có quá rõ ràng để ghi tài liệu này không? –

+0

Tài liệu sử dụng của công cụ này cung cấp một dòng duy nhất cho biết "theo thời gian: logging.debug (mem_top())", trong khi giải thích kết quả là trải nghiệm theo dõi lỗi thực tế của tác giả mà không có ngữ cảnh ... nói cho một dev chính xác những gì họ đang nhìn vào ... Tôi không gõ câu trả lời của bạn ... nó cho thấy nghi phạm cấp cao như được lập hoá đơn ... nó không cung cấp tài liệu đầy đủ để hiểu đầy đủ kết quả sử dụng ... cho ví dụ, trong kết quả "Giải thích kết quả" tại sao "GearmanJobRequest" rõ ràng là một vấn đề? không có giải thích cho lý do tại sao ... –

51

tôi đã cố gắng ra hầu hết các lựa chọn đề cập trước đây nhưng không tìm thấy gói nhỏ và trực quan này là tốt nhất: pympler

Đó là khá thẳng về phía trước để theo dõi đối tượng mà không được thu gom rác, kiểm tra ví dụ nhỏ này:

cài đặt gói qua pip install pympler

from pympler.tracker import SummaryTracker 
tracker = SummaryTracker() 

# ... some code you want to investigate ... 

tracker.print_diff() 

Đầu ra cho bạn thấy tất cả các đối tượng đã được thêm vào cùng với bộ nhớ mà chúng đã tiêu thụ.

Mẫu đầu ra:

        types | # objects | total size 
====================================== | =========== | ============ 
            list |  1095 | 160.78 KB 
            str |  1093 |  66.33 KB 
            int |   120 |  2.81 KB 
            dict |   3 |  840 B 
     frame (codename: create_summary) |   1 |  560 B 
      frame (codename: print_diff) |   1 |  480 B 

Gói này cung cấp một số tính năng hơn. Kiểm tra pympler's documentation, đặc biệt là phần Identifying memory leaks.

+1

Điều thú vị ... rò rỉ bộ nhớ của tôi thực sự biến mất khi tôi bắt đầu sử dụng pympler để thử theo dõi nó. Có lẽ một số vấn đề thu gom rác thải ... – sebpiq

+1

Cần lưu ý rằng 'pympler' có thể là ** SLOW **. Nếu bạn đang làm một cái gì đó bán thời gian thực, nó hoàn toàn có thể làm tê liệt hiệu suất ứng dụng của bạn. –

2

Theo như thực tiễn tốt nhất, hãy theo dõi các hàm đệ quy. Trong trường hợp của tôi, tôi gặp phải vấn đề với đệ quy (nơi không cần phải có). Một ví dụ đơn giản về những gì tôi đang làm:

def my_function(): 
    # lots of memory intensive operations 
    # like operating on images or huge dictionaries and lists 
    ..... 
    my_flag = True 
    if my_flag: # restart the function if a certain flag is true 
     my_function() 

def main(): 
    my_function() 

hoạt động theo cách đệ quy này sẽ không kích hoạt thu gom rác thải và dọn dẹp các phần còn lại của các chức năng, như vậy mỗi lần thông qua việc sử dụng bộ nhớ đang tăng trưởng và phát triển.

Giải pháp của tôi là kéo cuộc gọi đệ quy ra khỏi hàm my_function() và xử lý chính() khi gọi lại. theo cách này, hàm sẽ tự động kết thúc và tự dọn dẹp.

def my_function(): 
    # lots of memory intensive operations 
    # like operating on images or huge dictionaries and lists 
    ..... 
    my_flag = True 
    ..... 
    return my_flag 

def main(): 
    result = my_function() 
    if result: 
     my_function() 
+4

Sử dụng đệ quy theo cách này cũng sẽ bị ngắt nếu bạn nhấn giới hạn chiều sâu đệ quy vì Python không tối ưu hóa các cuộc gọi đuôi. Theo mặc định, đây là 1000 cuộc gọi đệ quy. –

3

Để phát hiện và định vị rò rỉ bộ nhớ cho các quy trình chạy dài, ví dụ: trong môi trường sản xuất, giờ đây bạn có thể sử dụng stackimpact. Nó sử dụng tracemalloc bên dưới. Thông tin thêm trong this post.

enter image description here

4

Tracemalloc module được tích hợp như một built-in mô-đun bắt đầu từ Python 3.4, và appearently, nó cũng có sẵn cho các phiên bản trước của Python như a third-party library (đã không kiểm tra nó mặc dù).

Mô-đun này có thể xuất ra các tệp và dòng chính xác phân bổ nhiều bộ nhớ nhất. IMHO, thông tin này vô cùng có giá trị hơn số lượng phiên bản được phân bổ cho từng loại (kết quả là rất nhiều bộ dữ liệu 99% thời gian, đó là một đầu mối, nhưng hầu như không giúp được trong hầu hết các trường hợp).

Tôi khuyên bạn nên sử dụng tracemalloc kết hợp với pyrasite. 9 lần trong số 10, chạy top 10 snippet trong một pyrasite-shell sẽ cung cấp cho bạn đủ thông tin và gợi ý để khắc phục sự cố rò rỉ trong vòng 10 phút. Tuy nhiên, nếu bạn vẫn không thể tìm thấy nguyên nhân rò rỉ, pyrasite-shell kết hợp với các công cụ khác được đề cập trong chủ đề này có thể sẽ cung cấp cho bạn một số gợi ý nữa. Bạn cũng nên xem xét tất cả những người trợ giúp thêm được cung cấp bởi pyrasite (chẳng hạn như trình xem bộ nhớ).