Python: отладка Утечки памяти

Массив массивов (зубчатые массивы) быстрее, чем многомерные массивы и может использоваться эффективнее. Многомерные массивы имеют более хороший синтаксис.

, Если Вы пишете некоторому простому использованию кода зубчатые и многомерные массивы и затем осматриваете скомпилированный блок с дизассемблером IL, Вы будете видеть, что устройство хранения данных и извлечение от зубчатого (или единственный размерный) массивы являются простыми инструкциями IL, в то время как те же операции для многомерных массивов являются вызовами метода, которые всегда медленнее.

Рассматривают следующие методы:

static void SetElementAt(int[][] array, int i, int j, int value)
{
    array[i][j] = value;
}

static void SetElementAt(int[,] array, int i, int j, int value)
{
    array[i, j] = value;
}

Их IL будет следующим:

.method private hidebysig static void  SetElementAt(int32[][] 'array',
                                                    int32 i,
                                                    int32 j,
                                                    int32 'value') cil managed
{
  // Code size       7 (0x7)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  ldelem.ref
  IL_0003:  ldarg.2
  IL_0004:  ldarg.3
  IL_0005:  stelem.i4
  IL_0006:  ret
} // end of method Program::SetElementAt

.method private hidebysig static void  SetElementAt(int32[0...,0...] 'array',
                                                    int32 i,
                                                    int32 j,
                                                    int32 'value') cil managed
{
  // Code size       10 (0xa)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  ldarg.1
  IL_0002:  ldarg.2
  IL_0003:  ldarg.3
  IL_0004:  call       instance void int32[0...,0...]::Set(int32,
                                                           int32,
                                                           int32)
  IL_0009:  ret
} // end of method Program::SetElementAt

, Когда использование неровно оборвало массивы, можно легко выполнить такие операции, как подкачка строки и строка изменяют размеры. Возможно, в некоторых случаях использование многомерных массивов будет более безопасным, но даже Microsoft FxCop сообщает, что зубчатые массивы должны использоваться вместо многомерного при использовании его для анализа проектов.

24
задан Paul Tarjan 27 August 2009 в 18:17
поделиться

6 ответов

Является ли DEBUG = False в settings.py?

Если нет, Django с радостью сохранит все SQL-запросы, которые вы делаете, которые складываются.

20
ответ дан 28 November 2019 в 22:40
поделиться

Have you tried gc.set_debug() ?

You need to ask yourself simple questions:

  • Am I using objects with __del__ methods? Do I absolutely, unequivocally, need them?
  • Can I get reference cycles in my code? Can't we break these circles before getting rid of the objects?

See, the main issue would be a cycle of objects containing __del__ methods:

import gc

class A(object):
    def __del__(self):
        print 'a deleted'
        if hasattr(self, 'b'):
            delattr(self, 'b')

class B(object):
    def __init__(self, a):
        self.a = a
    def __del__(self):
        print 'b deleted'
        del self.a


def createcycle():
    a = A()
    b = B(a)
    a.b = b
    return a, b

gc.set_debug(gc.DEBUG_LEAK)

a, b = createcycle()

# remove references
del a, b

# prints:
## gc: uncollectable <A 0x...>
## gc: uncollectable <B 0x...>
## gc: uncollectable <dict 0x...>
## gc: uncollectable <dict 0x...>
gc.collect()

# to solve this we break explicitely the cycles:
a, b = createcycle()
del a.b

del a, b

# objects are removed correctly:
## a deleted
## b deleted
gc.collect()

I would really encourage you to flag objects / concepts that are cycling in your application and focus on their lifetime: when you don't need them anymore, do we have anything referencing it?

Even for cycles without __del__ methods, we can have an issue:

import gc

# class without destructor
class A(object): pass

def createcycle():
    # a -> b -> c 
    # ^         |
    # ^<--<--<--|
    a = A()
    b = A()
    a.next = b
    c = A()
    b.next = c
    c.next = a
    return a, b, b

gc.set_debug(gc.DEBUG_LEAK)

a, b, c = createcycle()
# since we have no __del__ methods, gc is able to collect the cycle:

del a, b, c
# no panic message, everything is collectable:
##gc: collectable <A 0x...>
##gc: collectable <A 0x...>
##gc: collectable <dict 0x...>
##gc: collectable <A 0x...>
##gc: collectable <dict 0x...>
##gc: collectable <dict 0x...>
gc.collect()

a, b, c = createcycle()

# but as long as we keep an exterior ref to the cycle...:
seen = dict()
seen[a] = True

# delete the cycle
del a, b, c
# nothing is collected
gc.collect()

If you have to use "seen"-like dictionaries, or history, be careful that you keep only the actual data you need, and no external references to it.

I'm a bit disappointed now by set_debug, I wish it could be configured to output data somewhere else than to stderr, but hopefully that should change soon.

6
ответ дан 28 November 2019 в 22:40
поделиться

См. это отличное сообщение в блоге Неда Батчелдера о том, как они отследили реальную утечку памяти в Таббло HP. Классика, которую стоит прочитать.

5
ответ дан 28 November 2019 в 22:40
поделиться

Я думаю, вам следует использовать другие инструменты. По-видимому, полученная вами статистика касается только объектов GC (т.е. объектов, которые могут участвовать в циклах); в частности, в нем отсутствуют строки.

Я рекомендую использовать Pympler ; это должно предоставить вам более подробную статистику.

1
ответ дан 28 November 2019 в 22:40
поделиться

Do you use any extension? They are a wonderful place for memory leaks, and will not be tracked by python tools.

1
ответ дан 28 November 2019 в 22:40
поделиться

Попробуйте Guppy .

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

0
ответ дан 28 November 2019 в 22:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: