Как профилировать использование памяти в Python?
недавно я заинтересовался алгоритмами и начал изучать их, написав наивную реализацию, а затем оптимизируя ее различными способами.
Я уже знаком со стандартным модулем Python для профилирования времени выполнения (для большинства вещей, которые я нашел, достаточно магической функции timeit в IPython), но меня также интересует использование памяти, поэтому я также могу изучить эти компромиссы (например, стоимость кэширования таблицы ранее вычисленных значений против пересчитывая их по мере необходимости). Есть ли модуль, который будет профилировать использование памяти данной функции для меня?
6 ответов:
на этот вопрос уже ответили здесь: Python Memory profiler
в основном вы делаете что-то вроде этого (взято с гуппи-ЧП):
>>> from guppy import hpy; h=hpy() >>> h.heap() Partition of a set of 48477 objects. Total size = 3265516 bytes. Index Count % Size % Cumulative % Kind (class / dict of class) 0 25773 53 1612820 49 1612820 49 str 1 11699 24 483960 15 2096780 64 tuple 2 174 0 241584 7 2338364 72 dict of module 3 3478 7 222592 7 2560956 78 types.CodeType 4 3296 7 184576 6 2745532 84 function 5 401 1 175112 5 2920644 89 dict of class 6 108 0 81888 3 3002532 92 dict (no owner) 7 114 0 79632 2 3082164 94 dict of type 8 117 0 51336 2 3133500 96 type 9 667 1 24012 1 3157512 97 __builtin__.wrapper_descriptor <76 more rows. Type e.g. '_.more' to view.> >>> h.iso(1,[],{}) Partition of a set of 3 objects. Total size = 176 bytes. Index Count % Size % Cumulative % Kind (class / dict of class) 0 1 33 136 77 136 77 dict (no owner) 1 1 33 28 16 164 93 list 2 1 33 12 7 176 100 int >>> x=[] >>> h.iso(x).sp 0: h.Root.i0_modules['__main__'].__dict__['x'] >>>
Python 3.4 включает в себя новый модуль:
tracemalloc
. Он предоставляет подробную статистику о том, какой код выделения памяти. Вот пример, который отображает три верхние строки, выделяющие память.from collections import Counter import linecache import os import tracemalloc def display_top(snapshot, key_type='lineno', limit=3): snapshot = snapshot.filter_traces(( tracemalloc.Filter(False, "<frozen importlib._bootstrap>"), tracemalloc.Filter(False, "<unknown>"), )) top_stats = snapshot.statistics(key_type) print("Top %s lines" % limit) for index, stat in enumerate(top_stats[:limit], 1): frame = stat.traceback[0] # replace "/path/to/module/file.py" with "module/file.py" filename = os.sep.join(frame.filename.split(os.sep)[-2:]) print("#%s: %s:%s: %.1f KiB" % (index, filename, frame.lineno, stat.size / 1024)) line = linecache.getline(frame.filename, frame.lineno).strip() if line: print(' %s' % line) other = top_stats[limit:] if other: size = sum(stat.size for stat in other) print("%s other: %.1f KiB" % (len(other), size / 1024)) total = sum(stat.size for stat in top_stats) print("Total allocated size: %.1f KiB" % (total / 1024)) tracemalloc.start() counts = Counter() fname = '/usr/share/dict/american-english' with open(fname) as words: words = list(words) for word in words: prefix = word[:3] counts[prefix] += 1 print('Top prefixes:', counts.most_common(3)) snapshot = tracemalloc.take_snapshot() display_top(snapshot)
и вот результаты:
Top prefixes: [('con', 1220), ('dis', 1002), ('pro', 809)] Top 3 lines #1: scratches/memory_test.py:37: 6527.1 KiB words = list(words) #2: scratches/memory_test.py:39: 247.7 KiB prefix = word[:3] #3: scratches/memory_test.py:40: 193.0 KiB counts[prefix] += 1 4 other: 4.3 KiB Total allocated size: 6972.1 KiB
когда утечка памяти утечка?
этот пример отлично подходит, когда память все еще удерживается в конце вычисления, но иногда у вас есть код, который выделяет много из памяти, а затем освобождает все это. Технически это не утечка памяти, но она использует больше памяти, чем вы думаете. Как вы можете отслеживать использование памяти, когда это все выйдет? Если это ваш код, вы, вероятно, можете добавить код отладки, чтобы делать снимки во время его работы. Если нет, можно запустить фоновый поток для мониторинга использования памяти во время выполнения основного потока.
вот предыдущий пример, где код был перемещен в
для действительно простого подхода попробуйте:
import resource def using(point=""): usage=resource.getrusage(resource.RUSAGE_SELF) return '''%s: usertime=%s systime=%s mem=%s mb '''%(point,usage[0],usage[1], (usage[2]*resource.getpagesize())/1000000.0 )
просто вставить
using("Label")
где вы хотите увидеть, что происходит.
Я вы только хотите посмотреть на использование памяти объекта, (ответ на вопрос)
есть модуль под названием Pympler, которая содержит
asizeof
модуль.использовать следующим образом:
from pympler import asizeof asizeof.asizeof(my_object)
в отличие от
sys.getsizeof
, это работает на самостоятельно созданных объектов.>>> asizeof.asizeof(tuple('bcd')) 200 >>> asizeof.asizeof({'foo': 'bar', 'baz': 'bar'}) 400 >>> asizeof.asizeof({}) 280 >>> asizeof.asizeof({'foo':'bar'}) 360 >>> asizeof.asizeof('foo') 40 >>> asizeof.asizeof(Bar()) 352 >>> asizeof.asizeof(Bar().__dict__) 280
>>> help(asizeof.asizeof) Help on function asizeof in module pympler.asizeof: asizeof(*objs, **opts) Return the combined size in bytes of all objects passed as positional arguments.
может это поможет:
посмотреть дополнительные>pip install gprof2dot sudo apt-get install graphviz gprof2dot -f pstats profile_for_func1_001 | dot -Tpng -o profile.png def profileit(name): """ @profileit("profile_for_func1_001") """ def inner(func): def wrapper(*args, **kwargs): prof = cProfile.Profile() retval = prof.runcall(func, *args, **kwargs) # Note use of name from outer scope prof.dump_stats(name) return retval return wrapper return inner @profileit("profile_for_func1_001") def func1(...)
Ниже приведен простой декоратор функций, который позволяет отслеживать, сколько памяти процесс потребляется до вызова функции, после вызова функции, и в чем разница:
import time import os import psutil def elapsed_since(start): return time.strftime("%H:%M:%S", time.gmtime(time.time() - start)) def get_process_memory(): process = psutil.Process(os.getpid()) return process.get_memory_info().rss def profile(func): def wrapper(*args, **kwargs): mem_before = get_process_memory() start = time.time() result = func(*args, **kwargs) elapsed_time = elapsed_since(start) mem_after = get_process_memory() print("{}: memory before: {:,}, after: {:,}, consumed: {:,}; exec time: {}".format( func.__name__, mem_before, mem_after, mem_after - mem_before, elapsed_time)) return result return wrapper
мой блог, который описывает все подробности.