Почему добавление списка к себе, а затем удаление приводит к утечке памяти - PullRequest
5 голосов
/ 04 ноября 2019

Я нашел этот фрагмент обнаружения утечки памяти и интересовался утечкой памяти, которую он сгенерировал.

import gc

def dump_garbage():
    """
    show us what's the garbage about
    """

    # force collection
    print("\nGARBAGE:")
    gc.collect()

    print("\nGARBAGE OBJECTS:")
    for x in gc.garbage:
        s = str(x)
        if len(s) > 80: s = s[:80]
        print(type(x),"\n  ", s)

if __name__=="__main__":
    import gc
    gc.enable()
    gc.set_debug(gc.DEBUG_LEAK)

    # make a leak
    l = []
    l.append(l)
    del l

    # show the dirt ;-)
    dump_garbage()

Чтобы проверить обнаружение утечки памяти gc, автор создал свой собственныймаленькая утечка памяти:

l = []
l.append(l)
del(l)

Почему это приведет к утечке? На мой взгляд, у меня был бы объект списка, а не объект вложенного списка, где внутренний является внешним, а затем удалял внешний. Разве gc не знает, чтобы удалить все ссылки на исходный список и, следовательно, привести к утечке внутреннего списка?

Ответы [ 2 ]

1 голос
/ 14 ноября 2019

(Редактирование моих предыдущих комментариев в ответ.)

Связанная статья написана в 2001 году. В те времена Python 2.x был новым, и многие, вероятно, все еще использовали Python 1.x.

Python 1.x полагался исключительно на подсчет ссылок для сборки мусора, и циклические ссылки являются примером учебника, когда это не удается. В Python 2.x добавлен этап обнаружения цикла, но остались некоторые складки, например, наличие __del__ метода, блокирующего сборщик мусора, поскольку он не может определить правильный порядок уничтожения. Начиная с Python 3.4, большинство морщин было сглажено .

Так почему код примера по-прежнему указывает на утечки? Он устанавливает флаг GC_DEBUG_LEAK, который, помимо прочего, явно указывает сборщику мусора держать недоступные объекты вокруг!

0 голосов
/ 04 ноября 2019

Скорее всего, это очень похоже на бесконечный цикл: хотя l = [] и l.append(l) компилятору не удается определить, является ли список [] или [[]] или [[[]]], поскольку список добавляется к самому себе.

Я надеюсь, что вы понимаете это, вы можете увидеть мой пример оболочки здесь:

>>> l = []
>>> l.append(l)
>>> l
[[...]]

#Then, again:

>>> l = []
>>> l.append(l)
>>> l.append(l)
>>> l

[[...], [...]]

>>> l[0], l[1]

([[...], [...]], [[...], [...]])

>>> l[0][0]

[[...], [...]]

>>> l[0][0][0]

[[...], [...]]    # and so on...

Итак, вы можете видеть, что l - это в основном и бесконечный список, и удаление списка infinte закончитсяутечка памяти (я не знаю причину, но вы можете копать глубже, если хотите ...)

Надеюсь, это помогло.

РЕДАКТИРОВАТЬ :
Оболочка действительно выводит текст [...], на всякий случай, если вам интересно.

...