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

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

Wykonanie powyższych na strukturze ODP RDF dump powoduje zwiększenie pamięci. Dlaczego? Rozumiem, że ElementTree nadal buduje drzewo analizy, aczkolwiek z węzłami potomnymi clear() ed. Jeśli jest to przyczyną tego sposobu użycia pamięci, czy istnieje sposób obejścia tego?Czy użycie pamięci powinno wzrosnąć podczas korzystania z ElementTree.iterparse() podczas czyszczenia() drzew?

+0

Proszę wyjaśnić "zawsze rosnące". Jeśli wykonasz powyższe czynności w pętli, czy użycie pamięci eksploduje? A może widzisz, że użycie wzrasta po zrobieniu tego jeden raz, nawet po uwolnieniu wszystkich obiektów? – wberry

+0

Mam na myśli to, że spodziewam się, że użycie pamięci dla powyższego programu pozostanie stałe. Zamiast tego pokazuje monotyczny wzrost. –

+0

uruchamianie powyższego w pętli nie ma żadnego efektu, ponieważ po prostu zużywa stdin. –

Odpowiedz

8

Jesteś clear każdy element, ale odniesienia do nich pozostają w głównym dokumencie. Tak więc poszczególne elementy nadal nie mogą być zbierane śmieci. Zobacz this discussion w dokumentacji ElementTree.

Rozwiązaniem jest usunięcie odniesienia do korzeni, tak jak poniżej:

# 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() 

Inną rzeczą, aby pamiętać o wykorzystaniu pamięci, które nie mogą mieć wpływ na swoją sytuację, jest to, że gdy VM alokuje pamięć do przechowywania sterty z systemu, generalnie nigdy nie oddaje tej pamięci. Większość maszyn wirtualnych Java działa również w ten sposób. Nie powinieneś oczekiwać, że rozmiar interpretera w top lub ps będzie się zmniejszał, nawet jeśli ta pamięć sterty jest nieużywana.

+0

Ach, tego właśnie chciałem usłyszeć. Zrozumiałem, że ET wciąż buduje drzewo, ale będąc dla niego nowym, nie wiedziałem, jak dostać się do jego źródła. Dzięki! –

0

Wpadłem na ten sam problem. Dokumentacja nie wyjaśnia nic. Problem w moim przypadku był następujący:

1) Wywołanie polecenia clear powoduje zwolnienie pamięci dla węzłów podrzędnych. Dokumentacja mówi, że uwalnia całą pamięć. Wyczyść nie zwalnia pamięci, dla której wywoływane jest usuwanie, ponieważ pamięć należy do nadrzędnego, który ją przydzielił. 2) Wywołanie root.clear(), które zależy od tego, czym jest root. Jeśli root jest rodzicem, to będzie działać. W przeciwnym razie nie zwolni pamięci.

Poprawka polegała na zachowaniu odniesienia do rodzica, a gdy nie jest już potrzebny węzeł, wywołujemy parent.remove (child_node). To działało i utrzymywało profil pamięci w kilku kilobajtach.

1

Jak wspomniano w odpowiedzi Kevina Guerry, strategia "root.clear()" w dokumentacji ElementTree usuwa tylko w pełni sparsowane dzieci z korzenia. Jeśli te dzieci kotwiczą ogromne gałęzie, nie jest to zbyt pomocne.

Dotknął on idealne rozwiązanie, ale nie dodawać żadnego kodu, więc tutaj jest przykład:

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 

Element zainteresowania nie będą miały elementy podrzędne; zostaną usunięte, gdy tylko zostaną wyświetlone ich znaczniki końcowe. Może to być OK, jeśli potrzebujesz tylko tekstu lub atrybutów elementu.

Jeśli chcesz zapytać o potomków elementu, musisz utworzyć dla niego pełną gałąź. W tym celu należy zachować flagę, zaimplementowaną jako licznik głębokości dla tych elementów. Wywołuj tylko .remove(), gdy głębokość wynosi zero:

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 
Powiązane problemy