Upgrade to Pro — share decks privately, control downloads, hide ads and more …

На что уходит память?

На что уходит память?

Константин Лопухин (ЧТД)

Я хочу поговорить о проблеме потребления памяти приложений на Python — как понять что происходит, и что делать, когда оно больше чем нам хотелось бы. Сначала мы посмотрим, как вообще Python работает с памятью внутри, как он взаимодействует с ОС, может ли он отдавать память. Затем рассмотрим инструменты для анализа потребления памяти, и научимся интерпретировать их результат. Разберем типичные ошибки, которые приводят к излишнему потреблению памяти, рассмотрим некоторые приемы, которые могут позволить его уменьшить даже при отсутствии явных ляпов. В отличие от темы анализа производительности, на тему анализа потребления памяти на удивление мало материала, в основном только ответы на stackoverflow, поэтому хочется попробовать систематизировать то, что удалось узнать.

Доклад был впервые представлен на Pycon Russia.

Moscow Python Meetup

June 18, 2014
Tweet

More Decks by Moscow Python Meetup

Other Decks in Programming

Transcript

  1. . . Проблема Теория Инструменты Решения Ограничение размера задачи Объем

    памяти может ограничить максимальный размер решаемой задачи Изменить алгоритм так, чтобы не все держать в памяти, часто сложно . . . 6
  2. . . Проблема Теория Инструменты Решения Делаем ненужную работу Тратим

    лишнюю память и: не в лезаем влезаем в кэш процессовра делаем лишнюю работы по выделению и сборке памяти . . . 7
  3. . . Проблема Теория Инструменты Решения I/O bound? Часто можно

    превратить I/O bound задачу в CPU или Memory bound, и увеличить производительность . . . 8
  4. . . Проблема Теория Инструменты Решения Ограничение числа процессов Хотим

    использовать все ядра сервера Типичный сервер: 8-256 Гб памяти 4-128 ядер, 1-2 процесса на ядро 0.5-5 Гб памяти на процесс . . . 10
  5. . . Проблема Теория Инструменты Решения Что такое память Один

    из основных ресурсов В ней храняться текущие данные программы, она быстра и конечна Скорость доступа: L1: 0.5 ns, RAM: 100 ns, SSD: 150 000 ns . . . 11
  6. . . Проблема Теория Инструменты Решения Что с ней происходит

    Выделение (плюс взаимодействие с ОС) Чтение/запись Освобождение (сборщик мусора - GC) . . . 12
  7. . . Проблема Теория Инструменты Решения Как она используется class

    Point(object): def __init__(self, x, y, vx, vy): self.x = x self.y = y self.vx = vx self.vy = vy . . . 13
  8. . . Проблема Теория Инструменты Решения Сборка мусора освобождение объектов,

    к которым у нас уже нет доступа бесконечная память - сборщик не был бы нужен/заметен Пример: s = 0.0 for _ in xrange(10000000): s = s + 0.34 . . . 16
  9. . . Проблема Теория Инструменты Решения Сборка мусора: CPython reference

    coun ng: если на объект нет ссылок, то память можно освободить но нужно уметь собирать и отдельно висящие циклы только если в циклах нет объектов с __del__ (см. gc.garbage) . . . 17
  10. . . Проблема Теория Инструменты Решения Циклы: пример class Node:

    def __init__(self, parent=None): self.parent = parent self.children = [] a = Node() a.children.append(Node(parent=a)) a = 1 . . . 18
  11. . . Проблема Теория Инструменты Решения Циклы: __del__ class Node:

    def __init__(self, parent=None): self.parent = parent self.children = [] def __del__(self): pass a = Node(); a.children.append(Node(parent=a)) a = 1 . . . 19
  12. . . Проблема Теория Инструменты Решения Циклы: __del__ class Node:

    def __init__(self, parent=None): self.parent = parent self.children = [] def __del__(self): pass a = Node(); a.children.append(Node(parent=a)) a = 1 >>> gc.collect(); gc.garbage [<__main__.Node instance at 0x10a0dd5f0>, <__main__.Node instance at 0x10a0dd680>] . . . 20
  13. . . Проблема Теория Инструменты Решения Освобождение памяти ” Improving

    Python's Memory Allocator“ Evan Jones http://www.evanjones.ca/memoryallocator/ . . . 27
  14. . . Проблема Теория Инструменты Решения Инструменты Сколько памяти используется?

    Какие объекты занимают память? Почему они занимают память? . . . 29
  15. . . Проблема Теория Инструменты Решения Статистика ОС включает память

    C exten ons включает shared libraries дополнительная информация: vmmap, pmap -d import resource resource.getrusage(resource.RUSAGE_SELF).ru_maxrss . . . 30
  16. . . Проблема Теория Инструменты Решения Статистика ОС starting vlist_blocker

    ... finished vlist_blocker in 11.8649010658 s vlist_blocker: memory before: 32 440 k after: 412 016 k delta: 379 576 k . . . 31
  17. . . Проблема Теория Инструменты Решения heapy CPython 2.x overhead:

    нет (не считая времени на анализ) анализ используемой памяти сложно понять причину/источник . . . 32
  18. . . Проблема Теория Инструменты Решения heapy from guppy import

    hpy hp = hpy() hp.setrelheap() ... ... h = hp.heap() print h . . . 33
  19. . . Проблема Теория Инструменты Решения heapy 8343695 objects. Total

    size = 401971888 bytes. Index Count % Size % Cumulative % Kind (class / dict o 0 3337416 40 160M 40 160M 40 datetime.datetime 1 1668744 20 146M 37 307M 76 tuple 2 3336983 40 80M 20 387M 96 int 3 25 0 14M 4 401M 100 list 4 144 0 56K 0 401M 100 unicode 5 147 0 52K 0 401M 100 dict (no owner) ... . . . 34
  20. . . Проблема Теория Инструменты Решения heapy (Pdb) print h[1].byid

    1668748 <tuple> objects. Total size = 146849176 bytes. Index Size % Cumulative % Address*Length 0 88 0.0 88 0.0 0x10c141050*4 ... 9 88 0.0 88 0.0 0x10c141368*4 <1668738 more rows. Type e.g. '_.more' to view.> (Pdb) print h[1].byid[0].theone (108, 108, datetime.datetime(1, 1, 1, 0, 0), datetime.datetime(9999, 12, 31, 23, 59, 59, 999999)) . . . 35
  21. . . Проблема Теория Инструменты Решения tracemalloc CPython 3.4 (есть

    порт для 2.7) overhead: ~2x и память и время отслеживание выделения памяти с точностью до строчки и traceback но как и с heapy, нужно ” поймать момент“ . . . 36
  22. . . Проблема Теория Инструменты Решения tracemalloc [ Top 10

    ] django/db/utils.py:106: size=344 MiB, count=8343028, average=43 B documents/utils.py:47: size=13.3 MiB, count=1, average=13.3 MiB <frozen importlib._bootstrap>:656: size=59.7 KiB, count=520, average=118 B django/db/backends/postgresql_psycopg2/operations.py:21 size=27.6 KiB, count=77, average=367 B ... . . . 37
  23. . . Проблема Теория Инструменты Решения Утечка 44 | values

    = [] 45 | for d in _blocks_iterator( 46 | blocks, vlist, field_name, model, log): 47 | values.append(d) 48 | yield d . . . 38
  24. . . Проблема Теория Инструменты Решения tracemalloc [ Top 10

    ] django/db/utils.py:106: size=160 KiB, count=2050, average=80 B <frozen importlib._bootstrap>:656: size=59.1 KiB, count=515, average=118 B django/db/backends/postgresql_psycopg2/operations.py:21 size=56.2 KiB, count=176, average=327 B django/db/backends/util.py:74: size=39.0 KiB, count=184, average=217 B django/db/backends/util.py:76: size=10.9 KiB, count=177, average=63 B . . . 39
  25. . . Проблема Теория Инструменты Решения Оптимизации: объекты class Point(object):

    def __init__(self, x, y, vx, vy): self.x = x self.y = y self.vx = vx self.vy = vy points = [Point(x=random(), y=random(), vx=random(), vy=random()) for _ in xrange(n)] . . . 41
  26. . . Проблема Теория Инструменты Решения __slots__ class Point(object): __slots__

    = ['x', 'y', 'vx', 'vy'] def __init__(self, x, y, vx, vy): self.x = x self.y = y self.vx = vx self.vy = vy . . . 43
  27. . . Проблема Теория Инструменты Решения struct class Point(object): __slots__

    = ['_data'] def __init__(self, x, y, vx, vy): self._data = struct.pack( '=dddd', x, y, vx, vy) @property def x(self): return struct.unpack( '=dddd', self._data)[0] . . . 46
  28. . . Проблема Теория Инструменты Решения cffi from cffi import

    FFI ffi = FFI() ffi.cdef(""" typedef struct { double x, y, vx, vy; } Point; """) points = ffi.new("Point[]", 10000000) . . . 47
  29. . . Проблема Теория Инструменты Решения Общая память mmap: https://docs.python.org/2/library/mmap.html

    mul processing: https: //docs.python.org/2/library/multiprocessing.html# sharing-state-between-processes http://stackoverflow.com/a/5550156/217088 . . . 49
  30. . . Проблема Теория Инструменты Решения Архитектурные решения вынос жадных

    до памяти операций в отдельный процесс (mul processing, Celery, ..., отдельный сервис) вынос общей памяти в отдельный процесс/БД (redis, memcached, ..., отдельный сервис) . . . 50
  31. . . Проблема Теория Инструменты Решения Ссылки: внутренности CPython Improving

    Python's Memory Allocator: http://www.evanjones.ca/memoryallocator/ Stepping Through CPython: http://www.youtube.com/watch?v=XGF3Qu4dUqk gc: https://docs.python.org/2/library/gc.html Why Python is Slow: Looking Under the Hood: http://jakevdp.github.io/blog/2014/05/09/ why-python-is-slow/ Python’s Innards: http://tech.blog.aknin.name/ category/my-projects/pythons-innards/ . . . 52
  32. . . Проблема Теория Инструменты Решения Ссылки: оптимизации в PyPy

    объекты: http://morepypy.blogspot.ru/2010/11/ efficiently-implementing-python-objects.html списки: http://morepypy.blogspot.ru/2011/10/ more-compact-lists-with-list-strategies.html . . . 53
  33. . . Проблема Теория Инструменты Решения Ссылки: инструменты Heapy: http://guppy-pe.sourceforge.net/

    http: //smira.ru/wp-content/uploads/2011/08/heapy.html Meliae: http://jam-bazaar.blogspot.ru/2009/11/ memory-debugging-with-meliae.html http://jam-bazaar.blogspot.ru/2010/08/ step-by-step-meliae.html . . . 54
  34. . . Проблема Теория Инструменты Решения Ссылки: tracemalloc Документация: https:

    //docs.python.org/3/library/tracemalloc.html PEP: http://legacy.python.org/dev/peps/pep-0454/ . . . 55