Утечка памяти Python - решена, но все еще озадачена - PullRequest
2 голосов
/ 06 апреля 2010

Я успешно отладил собственные проблемы с утечкой памяти. Однако я заметил очень странный случай.

    for fid, fv in freqDic.iteritems():
        outf.write(fid+"\t")                #ID
        for i, term in enumerate(domain):   #Vector
            tfidf = self.tf(term, fv) * self.idf( term, docFreqDic)
            if i == len(domain) - 1:
                outf.write("%f\n" % tfidf)
            else:
                outf.write("%f\t" % tfidf)
        outf.flush()
        print "Memory increased by", int(self.memory_mon.usage()) - startMemory

    outf.close()

def tf(self, term, freqVector):
    total = freqVector[TOTAL]
    if total == 0:
        return 0
    if term not in freqVector:      ##  When you don't have these lines memory leaks occurs
        return 0                    ##
    return float(freqVector[term]) / freqVector[TOTAL]


def idf(self, term, docFrequencyPerTerm):
    if term not in docFrequencyPerTerm:
        return 0        
    return math.log( float(docFrequencyPerTerm[TOTAL])/docFrequencyPerTerm[term])

В основном позвольте мне описать мою проблему: 1) я делаю вычисления tfidf 2) Я проследил, что источник утечек памяти происходит из defaultdict. 3) Я использую memory_mon из Как узнать текущее использование процессора и оперативной памяти в Python? 4) Причина моих утечек памяти заключается в следующем: а) в self.tf, если строки: если термин не в freqVector: возвращать 0, не добавляются, что приведет к утечке памяти. (Я сам проверил это с помощью memory_mon и заметил резкое увеличение памяти, которое продолжало увеличиваться)

Решение моей проблемы было 1), поскольку fv является defaultdict, любая ссылка на него, которая не найдена в fv, создаст запись. На очень большом домене это приведет к утечке памяти.

Я решил использовать dict вместо dict по умолчанию, и проблема с памятью исчезла.

Моя единственная загадка: поскольку fv создается в "for fid, fv в freqDic.iteritems ():" не следует ли уничтожать fv в конце каждого цикла for? Я попытался поместить gc.collect () в конец цикла for, но gc не смог собрать все (возвращает 0). Да, гипотеза верна, но память должна оставаться достаточно постоянной для цикла for, если циклы for уничтожают все временные переменные.

Вот как это выглядит с двумя строками в self.tf:

Memory increased by 12
Memory increased by 948
Memory increased by 28
Memory increased by 36
Memory increased by 36
Memory increased by 32
Memory increased by 28
Memory increased by 32
Memory increased by 32
Memory increased by 32
Memory increased by 40
Memory increased by 32
Memory increased by 32
Memory increased by 28

и без двух строчек:

Memory increased by 1652
Memory increased by 3576
Memory increased by 4220
Memory increased by 5760
Memory increased by 7296
Memory increased by 8840
Memory increased by 10456
Memory increased by 12824
Memory increased by 13460
Memory increased by 15000
Memory increased by 17448
Memory increased by 18084
Memory increased by 19628
Memory increased by 22080
Memory increased by 22708
Memory increased by 24248
Memory increased by 26704
Memory increased by 27332
Memory increased by 28864
Memory increased by 30404
Memory increased by 32856
Memory increased by 33552
Memory increased by 35024
Memory increased by 36564
Memory increased by 39016
Memory increased by 39924
Memory increased by 42104
Memory increased by 42724
Memory increased by 44268
Memory increased by 46720
Memory increased by 47352
Memory increased by 48952
Memory increased by 50428
Memory increased by 51964
Memory increased by 53508
Memory increased by 55960
Memory increased by 56584
Memory increased by 58404
Memory increased by 59668
Memory increased by 61208
Memory increased by 62744
Memory increased by 64400

Я с нетерпением жду вашего ответа

EDIT: Похоже, что моя терминология могла быть неправильной (или неверной).

  1. Утечка памяти, о которой я говорил, НЕ была сгенерирована из freqVector [term]. (Поиск несуществующего ключа в defaultdict).
  2. Фактическая утечка памяти, о которой я говорил, была утечка памяти из for fid, fv in freqDic.iteritems() !! Я знаю, что fv увеличился в размере из-за 1), но он все равно должен быть уничтожен в конце цикла! память не должна продолжать расширяться. Это не утечка памяти?

Ответы [ 3 ]

2 голосов
/ 06 апреля 2010

Итерация по freqDict не генерирует новые значения, но передает ссылки на значения, уже сохраненные в dict Это означает, что вы добавляете новые значения в fv, который удерживается freqDict даже после цикла.

Другим решением было бы очистить freqDict после зацикливания.

В общем, Python передает все по ссылке, хотя иногда это выглядит иначе. Строки и целые числа неизменны, и объект, который они представляют, заменяется, если они изменены.

1 голос
/ 06 апреля 2010

Я подозреваю, что использование памяти Python может увеличиваться, потому что числа с плавающей запятой также являются объектами в Python, и интерпретатор поддерживает свободный список чисел с плавающей точкой, который является неограниченным и бессмертным. Следовательно, всякий раз, когда вычисление с плавающей точкой приводит к появлению нового с плавающей точкой, чего раньше не было, Python выделяет новый объект с плавающей точкой в ​​списке freelist, а затем сохраняет объект на случай, если он понадобится позже.

Смотрите подобное обсуждение в трекере ошибок Python здесь .

0 голосов
/ 06 апреля 2010

Это не утечка памяти, так как память не протекает, она принимается по умолчанию, например

from collections import defaultdict

d = defaultdict(int)
for i in xrange(10**7):
    a = d[i]

Как вы думаете, это утечка памяти? Вы присваиваете значения dict, и из-за него должно увеличиться использование памяти, это похоже на это

d = {}
for i in xrange(10**7):
    d[i] = 0

, который не является утечкой памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...