2014-10-15 17 views
6

Tôi có tiện ích Python nằm trên một tệp tar.xz và xử lý từng tệp riêng lẻ. Đây là tệp nén 15MB, với 740MB dữ liệu không nén.Rò rỉ đối tượng TarInfo

Trên một máy chủ cụ thể có bộ nhớ rất hạn chế, chương trình bị lỗi vì chương trình hết bộ nhớ. Tôi đã sử dụng objgraph để xem các đối tượng nào được tạo. Nó chỉ ra rằng các trường hợp TarInfo không được phát hành. Vòng lặp chính là tương tự như sau:

with tarfile.open(...) as tar: 
    while True: 
     next = tar.next() 
     stream = tar.extractfile(next) 
     process_stream() 
     iter+=1 
     if not iter%1000: 
      objgraph.show_growth(limit=10) 

Đầu ra là rất phù hợp:

TarInfo  2040  +1000 
TarInfo  3040  +1000 
TarInfo  4040  +1000 
TarInfo  5040  +1000 
TarInfo  6040  +1000 
TarInfo  7040  +1000 
TarInfo  8040  +1000 
TarInfo  9040  +1000 
TarInfo 10040  +1000 
TarInfo 11040  +1000 
TarInfo 12040  +1000 

này tiếp tục cho đến khi tất cả 30.000 tập tin được xử lý.

Để đảm bảo, tôi đã nhận xét các dòng tạo luồng và xử lý luồng đó. Việc sử dụng bộ nhớ vẫn như cũ - Các cá thể TarInfo bị rò rỉ.

Tôi đang sử dụng Python 3.4.1 và hành vi này nhất quán trên Ubuntu, OS X và Windows.

Trả lời

5

Dường như điều này thực sự là do thiết kế. Đối tượng TarFile duy trì danh sách tất cả các đối tượng TarInfo chứa trong thuộc tính members. Mỗi lần bạn gọi next, đối tượng TarInfo nó chiết xuất từ ​​kho lưu trữ được thêm vào danh sách:

def next(self): 
    """Return the next member of the archive as a TarInfo object, when 
     TarFile is opened for reading. Return None if there is no more 
     available. 
    """ 
    self._check("ra") 
    if self.firstmember is not None: 
     m = self.firstmember 
     self.firstmember = None 
     return m 

    # Read the next block. 
    self.fileobj.seek(self.offset) 
    tarinfo = None 
    ... <snip> 

    if tarinfo is not None: 
     self.members.append(tarinfo) # <-- the TarInfo instance is added to members 

Danh sách members sẽ chỉ tiếp tục phát triển khi bạn trích xuất nhiều mặt hàng. Điều này cho phép sử dụng các phương pháp getmembersgetmember, nhưng chỉ gây phiền toái cho trường hợp sử dụng của bạn. Có vẻ như cách giải quyết tốt nhất là chỉ cần giữ thanh toán bù trừ thuộc tính members như bạn lặp (như đề xuất here):

with tarfile.open(...) as tar: 
    while True: 
     next = tar.next() 
     stream = tar.extractfile(next) 
     process_stream() 
     iter+=1 
     tar.members = [] # Clear members list 
     if not iter%1000: 
      objgraph.show_growth(limit=10) 
+0

Wow, tuyệt vời! Cảm ơn! – zmbq

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