утечка памяти в Python, утечка кадров - PullRequest
1 голос
/ 04 ноября 2010

У меня есть этот код, чтобы узнать имя файла, номер строки и функцию моей функции. Похоже, что утечка кадров, и я не понимаю, почему. Это просто сбивает меня с толку и моя утечка должна быть в другом месте?

        rv = "(unknown file)", 0, "(unknown function)"

            for f in inspect.stack()[1:]:
                if __file__ in f:
                    continue
                else:
                    rv = f[1:4]
                    break

        return rv

Я нигде не сохраняю ссылку на фрейм. Но это определенно утечка кадров:

> objcallgraph.show_most_common_types()
>tuple                      24798
>frame                      9601
>...

Обновление : Мои рамки определенно просочились. Я сделал предложение о gc.set_debug (), и фреймы очень медленно попадают в список gc.garbage. Даже не близко к тому, сколько создается, как показано в show_most_common_types (). У меня есть вопрос о области видимости, хотя, как указано выше, f не выходит из области видимости после цикла for? Потому что я только что попробовал это:


for f in range(20):
    l = 1

print f

и напечатано 19. Так может ли это быть f в цикле for? Это контрольный граф ссылки на фрейм, который был в моем списке gc.garbage:

alt text

Update2

Похоже, что сам модуль проверки содержит ссылки на фреймы. Это объект-граф обратной ссылки из живого фрейма, а не из списка мусора.

alt text

Ссылка здесь , потому что она слишком широкая.

Есть ли способ очистить модуль проверки? Где, черт возьми, эти кадры сохраняются = \

Ответы [ 2 ]

1 голос
/ 05 ноября 2010

Ну, я думаю, что нашел проблему. Кажется, это проблема модуля inspect и базового кода C в многопоточном приложении. Модуль с кодом выше импортируется из разных потоков. И этот второй график указывает на проблему.

alt text

function, указанный здесь в 3-м узле внизу, - inspect.getmodule (). Я не мог вместить все это там, и мне пришлось немного подрезать.

(Pdb) objgraph.at(3510928)
<cell at 0x359290: dict object at 0x3849c0>

А внутри диктата есть все кадры

(Pdb) objgraph.at(0x3849c0)

     {(<frame object at 0x97a288>, '/lib/python26.zip/logging/__init__.py'): <module 'logging' from '/lib/python26.zip/logging/__init__.py'>,
     (<frame object at 0x896288>, '/lib/python26.zip/logging/__init__.py'): <module 'logging' from '/lib/python26.zip/logging/__init__.py'>,
     (<frame object at 0xa621b0>, '/lib/python26.zip/logging/__init__.py'): <module 'logging' from '/lib/python26.zip/logging/__init__.py'>,
     (<frame object at 0x11266e8>, '/lib/python26.zip/logging/__init__.py'): <module 'logging' from '/lib/python26.zip/logging/__init__.py'>,
    ...}

И если вы получите внешние кадры всех этих кадров

(Pdb) inspect.getouterframes(objgraph.at(0x97a288))
[(<frame object at 0x97a288>, '/lib/python26.zip/logging/__init__.py', 1028, 'debug', ['            self._log(DEBUG, msg, args, **kwargs)\n'], 0),
 (<frame object at 0x794040>, '/lib/python26.zip/logging/__init__.py', 1505, 'debug', ['    root.debug(*((msg,)+args), **kwargs)\n'], 0),
 (<frame object at 0x794e58>, '/mmc/src/core/controller/main.py', 1046, '__startCharge', ['            self.chargeLock.release()\n'], 0),
 (<frame object at 0x5c4260>, '/mmc/src/core/controller/main.py', 1420, 'watchScheduleStartChargeCondition', ['                        ret = self.__startCharge(0, eventCode=eventCode)\n'], 0),
 (<frame object at 0x5c0dd0>, '/home/ephibian/Python2/_install/lib/python2.6/threading.py', 484, 'run', None, None),
 (<frame object at 0x5c3b48>, '/home/ephibian/Python2/_install/lib/python2.6/threading.py', 532, '__bootstrap_inner', None, None),
 (<frame object at 0x218170>, '/home/ephibian/Python2/_install/lib/python2.6/threading.py', 504, '__bootstrap', None, None)]

Все они указывают на метод __bootstrap в потоке. Я мог оказаться здесь не на том пути, но контекст некоторых из этих фреймов далеко не там, где я вызываю опубликованный мной метод.

1 голос
/ 04 ноября 2010

РЕДАКТИРОВАТЬ Я только что понял, что это неправильно, ссылки f и f_back указывают одинаково. Я оставлю это на случай, если это вдохновит кого-то другого:

Каждый кадр имеет указатель f_back, поэтому, когда вы устанавливаете f = inspect.stack()[1], тогда inspect.stack()[0][0].f_locals (который содержит f) теперь имеет ссылку на ...stack()[1], а ...stack()[1][0].f_back указывает на ...stack()[0][0]. Таким образом, вы создали циклическую ссылку, которая должна быть разрешена GC, а не просто счетчиком ссылок. GC не настроен на скорость создания объектов, поэтому вы потребляете все больше и больше памяти.

Вероятно, вы можете устранить круговую привязку, просто установив f = None на выходе из функции. Это нарушает круговую ссылку.

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