2012-04-09 24 views
6
import os 
import xml.etree.ElementTree as et 

for ev, el in et.iterparse(os.sys.stdin): 
    el.clear() 

Chạy ở trên cấu trúc ODP RDF dump dẫn đến bộ nhớ luôn tăng lên. Tại sao vậy? Tôi hiểu ElementTree vẫn xây dựng một cây phân tích, mặc dù với các nút con clear() ed. Nếu đó là nguyên nhân của mẫu sử dụng bộ nhớ này, có cách nào xung quanh nó không?Nên sử dụng bộ nhớ tăng khi sử dụng ElementTree.iterparse() khi xóa() ing cây?

+0

Hãy làm rõ "luôn tăng". Nếu bạn thực hiện thao tác trên trong một vòng lặp, việc sử dụng bộ nhớ có phát nổ không? Hay bạn chỉ thấy việc sử dụng tăng lên sau khi làm điều này một lần, ngay cả sau khi tất cả các đối tượng được giải phóng? – wberry

+0

Tôi có nghĩa là tôi mong đợi việc sử dụng bộ nhớ cho chương trình ở trên không thay đổi. Thay vào đó, nó cho thấy một sự gia tăng độc đáo. –

+0

chạy trên trong một vòng lặp không có hiệu lực, vì nó sẽ chỉ tiêu thụ stdin. –

Trả lời

8

Bạn đang clear ing từng phần tử nhưng tham chiếu đến chúng vẫn còn trong tài liệu gốc. Vì vậy, các yếu tố cá nhân vẫn không thể được thu gom rác thải. Xem this discussion trong tài liệu ElementTree.

Giải pháp là để xóa tài liệu tham khảo trong thư mục gốc, như vậy:

# get an iterable 
context = iterparse(source, events=("start", "end")) 

# turn it into an iterator 
context = iter(context) 

# get the root element 
event, root = context.next() 

for event, elem in context: 
    if event == "end" and elem.tag == "record": 
     ... process record elements ... 
     root.clear() 

Một điều cần ghi nhớ về việc sử dụng bộ nhớ, mà có thể không được làm ảnh hưởng đến tình hình của bạn, là một khi VM cấp phát bộ nhớ để lưu trữ đống từ hệ thống, nó thường không bao giờ đưa lại bộ nhớ đó. Hầu hết các máy ảo Java đều hoạt động theo cách này. Vì vậy, bạn không nên mong đợi kích thước của thông dịch viên trong top hoặc ps để bao giờ giảm, ngay cả khi bộ nhớ heap đó không được sử dụng.

+0

Ah, đó là điều tôi muốn nghe. Tôi hiểu ET đã xây dựng vẫn còn xây dựng một cái cây, nhưng là mới với nó, tôi không biết làm thế nào để có được ở gốc của nó. Cảm ơn! –

0

Tôi đã gặp sự cố tương tự. Các tài liệu không làm cho mọi thứ rất rõ ràng. Vấn đề trong trường hợp của tôi là:

1) Gọi rõ ràng sẽ giải phóng bộ nhớ cho các nút con. Tài liệu nói rằng nó phát hành tất cả bộ nhớ. Clear không giải phóng bộ nhớ mà rõ ràng được gọi, bởi vì bộ nhớ đó thuộc về cha mẹ đã cấp phát bộ nhớ đó. 2) Gọi root.clear(), điều đó phụ thuộc vào root là gì. Nếu root là cha mẹ thì nó sẽ hoạt động. Nếu không, nó sẽ không giải phóng bộ nhớ.

Khắc phục là giữ tham chiếu đến phụ huynh và khi chúng tôi không còn cần nút, chúng tôi gọi parent.remove (child_node). Điều này làm việc và nó giữ hồ sơ bộ nhớ tại một vài KB.

1

Như đã đề cập trong câu trả lời của Kevin Guerra, chiến lược "root.clear()" trong tài liệu ElementTree chỉ xóa các phần tử được phân tích cú pháp hoàn toàn của thư mục gốc. Nếu những đứa trẻ đó đang neo đậu những cành cây lớn, nó không phải là rất hữu ích.

Ông đề cập đến giải pháp lý tưởng, nhưng không gửi bất kỳ mã, vì vậy đây là một ví dụ:

element_stack = [] 
context = ET.iterparse(stream, events=('start', 'end')) 
for event, elem in context: 
    if event == 'start': 
     element_stack.append(elem) 
    elif event == 'end': 
     element_stack.pop() 
     # see if elem is one of interest and do something with it here 
     if element_stack: 
      element_stack[-1].remove(elem) 
del context 

Yếu tố hấp dẫn sẽ không có phần tử con; chúng sẽ bị xóa ngay khi thẻ kết thúc của chúng được xem. Điều này có thể được chấp nhận nếu tất cả những gì bạn cần là văn bản hoặc thuộc tính của phần tử.

Nếu bạn muốn truy vấn vào con cháu của phần tử, bạn cần tạo một nhánh đầy đủ cho nó. Đối với điều này, duy trì một lá cờ, thực hiện như một truy cập chiều sâu cho những yếu tố đó. Chỉ gọi .remove() khi độ sâu là 0:

element_stack = [] 
interesting_element_depth = 0 
context = ET.iterparse(stream, events=('start', 'end')) 
for event, elem in context: 
    if event == 'start': 
     element_stack.append(elem) 
     if elem.tag == 'foo': 
      interesting_element_depth += 1 
    elif event == 'end': 
     element_stack.pop() 
     if elem.tag == 'foo': 
      interesting_element_depth -= 1 
      # do something with elem and its descendants here 
     if element_stack and not interesting_element_depth: 
      element_stack[-1].remove(elem) 
del context 
Các vấn đề liên quan