Как я могу проверить использование памяти объектами в iPython?

Я использую iPython для запуска своего кода. Интересно, есть ли какой-нибудь модуль или команда, которые позволили бы мне проверить использование памяти объектом. Например:

In [1]: a = range(10000)
In [2]: %memusage a
Out[2]: 1MB

Что-то вроде %memusage <object> и вернуть память, используемую объектом.

Дубликат

Узнайте, сколько памяти используется объектом в Python


person Ross    schedule 19.02.2009    source источник
comment
Дубликат: stackoverflow.com/questions/33978/, stackoverflow.com/questions/512893/   -  person S.Lott    schedule 19.02.2009
comment
Также по теме: stackoverflow.com/questions/135664/   -  person Constantin    schedule 19.02.2009
comment
Прости. Я просто хочу спросить, есть ли какая-либо реализация этих функций в ipython или модуль для добавления волшебной функции в ipython (поскольку я использую это для большого тестирования).   -  person Ross    schedule 20.02.2009
comment
Возможный дубликат Как определить размер объект в Python?   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 08.06.2017


Ответы (4)


К сожалению, это невозможно, но есть несколько способов приблизиться к ответу:

  1. для очень простых объектов (например, целых чисел, строк, чисел с плавающей запятой, двойников), которые представлены более или менее как простые типы языка C, вы можете просто вычислить количество байтов, как с Решение Джона Малдера.

  2. Для более сложных объектов хорошим приближением является сериализация объекта в строку с помощью cPickle.dumps. Длина строки является хорошим приближением к объему памяти, необходимому для хранения объекта.

Есть одна большая загвоздка с решением 2: объекты обычно содержат ссылки на другие объекты. Например, dict содержит строковые ключи и другие объекты в качестве значений. Эти другие объекты могут использоваться совместно. Поскольку pickle всегда пытается выполнить полную сериализацию объекта, он всегда будет переоценивать объем памяти, необходимый для хранения объекта.

person Salim Fadhley    schedule 19.02.2009
comment
Но если вы составите список, содержащий все интересующие вас корневые объекты, завышения не будет. - person Constantin; 19.02.2009
comment
Большое Вам спасибо. Но мне интересно, будет ли рассол делать какое-либо сжатие или нет. - person Ross; 20.02.2009
comment
Нет, рассол не сжимается. Это просто устраняет избыточность. - person Salim Fadhley; 20.02.2009
comment
На SO нет «вышеуказанного» решения. - person Pierre Mourlanne; 24.05.2013
comment
Салим: Устранение избыточности - одно из определений сжатия :) Недавно я попытался создать массив из 10 000 похожих строк и с помощью Pickle посмотреть на потребление памяти. Он сохраняет его как строку один раз, а затем по одному байту на каждое повторение. Однако это ничего не говорит мне о представлении этой строки во внутренней памяти (оно может быть таким же, или может быть другим). - person Stian Håklev; 20.12.2013

Если вы используете массив numpy, вы можете использовать атрибут ndarray.nbytes для оценки его размера в памяти:

from pylab import *   
d = array([2,3,4,5])   
d.nbytes
#Output: 32
person HoWil    schedule 23.03.2013

ОБНОВЛЕНИЕ. Вот еще один, возможно, более подробный рецепт для оценки размера объекта Python.

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

Предлагаемое решение состоит в том, чтобы написать свое собственное ... используя некоторые оценки известного размера примитивов, накладных расходов объекта Python и размеров встроенных типов контейнеров.

Поскольку код не такой длинный, вот его прямая копия:

def sizeof(obj):
    """APPROXIMATE memory taken by some Python objects in 
    the current 32-bit CPython implementation.

    Excludes the space used by items in containers; does not
    take into account overhead of memory allocation from the
    operating system, or over-allocation by lists and dicts.
    """
    T = type(obj)
    if T is int:
        kind = "fixed"
        container = False
        size = 4
    elif T is list or T is tuple:
        kind = "variable"
        container = True
        size = 4*len(obj)
    elif T is dict:
        kind = "variable"
        container = True
        size = 144
        if len(obj) > 8:
            size += 12*(len(obj)-8)
    elif T is str:
        kind = "variable"
        container = False
        size = len(obj) + 1
    else:
        raise TypeError("don't know about this kind of object")
    if kind == "fixed":
        overhead = 8
    else: # "variable"
        overhead = 12
    if container:
        garbage_collector = 8
    else:
        garbage_collector = 0
    malloc = 8 # in most cases
    size = size + overhead + garbage_collector + malloc
    # Round to nearest multiple of 8 bytes
    x = size % 8
    if x != 0:
        size += 8-x
        size = (size + 8)
    return size
person John Mulder    schedule 19.02.2009
comment
Это довольно жестко запрограммированное решение. Это не сработает, если у нас есть список больших словарей или любая другая структура данных! - person user2685079; 12.06.2017

Я пытался понять, как это сделать для себя. Я пробовал несколько решений на этой и других страницах. Затем я немного поискал и наткнулся на https://ipython-books.github.io/44-profiling-the-memory-usage-of-your-code-with-memory_profiler/, который, кажется, дает альтернативное решение. Суть решения: используйте %mprun в ipython.

  1. Сначала установите memory_profiler: pip install memory_profiler
  2. Запустите ipython и загрузите memory_profiler:% load_ext memory_profiler
  3. Создайте функцию в физическом файле, скажем, myfunc.py (важно: % mprun можно использовать только для функций, определенных в физических файлах). Создайте рассматриваемый объект в функции, например:
# myfunc.py
def myfunc():
    # create the object, e.g.
    a = [*range(10000)]
  1. Бегать
from myfunc import myfunc
%mprun -T mprof -f myfunc myfunc()

который генерирует файл mprof. Также отображается контент:

Line #    Mem usage    Increment   Line Contents
================================================
     1     49.1 MiB     49.1 MiB   def myfunc():
     2                                 # create the object, e.g.
     3     49.4 MiB      0.3 MiB       a = [*range(10000)]

Из строки 3 мы знаем, что память, используемая a, составляет 0,3 МБ.

Попробуем a = [*range(100000)]:

# myfunc1.py
def myfunc1():
    # create the object, e.g.
    a = [*range(100000)]

Бегать

from myfunc1 import myfunc1
%mprun -T mprof1 -f myfunc1 myfunc1()

Line #    Mem usage    Increment   Line Contents
================================================
     1     49.2 MiB     49.2 MiB   def myfunc1():
     2                                 # create the object, e.g.
     3     52.3 MiB      3.0 MiB       a = [*range(100000)]

похоже, соответствует нашим ожиданиям.

person mikey    schedule 13.10.2019