Общая память, используемая процессом Python?


266

Есть ли способ для программы Python определить, сколько памяти она использует в настоящее время? Я видел дискуссии об использовании памяти для одного объекта, но мне нужно общее использование памяти для процесса, чтобы я мог определить, когда необходимо начать отбрасывать кэшированные данные.

Ответы:


303

Вот полезное решение, которое работает для различных операционных систем, включая Linux, Windows 7 и т.д .:

import os
import psutil
process = psutil.Process(os.getpid())
print(process.memory_info().rss)  # in bytes 

На моем текущем Python 2.7, установленном с psutil 5.6.3, последняя строка должна быть

print(process.memory_info()[0])

вместо этого (произошло изменение в API).

Примечание: сделайте, pip install psutilесли он еще не установлен.


3
psutilкросс - платформенный и может возвращать то же значение , как psинструмент командной строки: pythonhosted.org/psutil/#psutil.Process.memory_info
амосс

1
"( psutil) в настоящее время поддерживает Linux, Windows, OSX, FreeBSD и Sun Solaris, как 32-разрядные, так и 64-разрядные архитектуры, с версиями Python от 2,6 до 3,4" из Документации
Сесилия

2
Почему этот номер не совпадает с номером в проводнике процессов? Число от psutil всегда кажется больше примерно на 10%.
словами

39
Обратите внимание, что psutil отсутствует в стандартной библиотеке
grisaitis

12
Для последних версий psutil, psutil.Process()эквивалентно psutil.Process(os.getpid()). Это еще одна вещь, которую вы должны помнить, чтобы напечатать.
rnorris

209

Для систем на основе Unix (Linux, Mac OS X, Solaris) вы можете использовать getrusage()функцию из стандартного библиотечного модуля resource. Полученный объект имеет атрибут ru_maxrss, который дает пиковое использование памяти для вызывающего процесса:

>>> resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
2656  # peak memory usage (kilobytes on Linux, bytes on OS X)

Документы Python не помнят единицы измерения. Обратитесь к man getrusage.2странице вашей конкретной системы, чтобы проверить значение единицы измерения. В Ubuntu 18.04 единица измерения указана в килобайтах. В Mac OS X это байты.

getrusage()Функция также может быть дана , resource.RUSAGE_CHILDRENчтобы получить использование для дочерних процессов, а также (в некоторых системах) resource.RUSAGE_BOTHдля общего (я и ребенка) использования процесса.

Если вы заботитесь только о Linux, вы также можете прочитать файл /proc/self/statusили, /proc/self/statmкак описано в других ответах на этот и этот вопросы .


2
Ладно сделаем Я не был уверен, есть ли у SO процесс слияния вопросов или что. Дубликат поста должен был частично показать людям, что существует стандартное решение для библиотеки по обоим вопросам ... и частично для представителя. ;) Должен ли я удалить этот ответ?
Натан Крейк

6
Mac OS определенно возвращает RSS в байтах, Linux возвращает его в килобайтах.
Нил

13
Единицы НЕ в килобайтах. Это зависит от платформы, поэтому вы должны использовать resource.getpagesize (), чтобы узнать. Данные документы Python ( docs.python.org/2/library/resource.html#resource-usage ) на самом деле очень ясны. Это 4096 в моей коробке.
Бен Лин

5
@BenLin Эти документы на Python явно ошибочны, или в версии для Mac есть ошибка. Единица, используемая getrusage, и значение, возвращаемое getpagesize, определенно отличаются.
Андрей

7
Вопрос задан для текущего использования. Обратите внимание, что это максимальное использование. (Все еще полезный ответ, просто предупреждаю людей, которые ошибочно копируют и вставляют это.)
Люк

65

В Windows вы можете использовать WMI ( домашняя страница , cheeseshop ):


def memory():
    import os
    from wmi import WMI
    w = WMI('.')
    result = w.query("SELECT WorkingSet FROM Win32_PerfRawData_PerfProc_Process WHERE IDProcess=%d" % os.getpid())
    return int(result[0].WorkingSet)

В Linux (из кулинарной книги python http://code.activestate.com/recipes/286222/ :

import os
_proc_status = '/proc/%d/status' % os.getpid()

_scale = {'kB': 1024.0, 'mB': 1024.0*1024.0,
          'KB': 1024.0, 'MB': 1024.0*1024.0}

def _VmB(VmKey):
    '''Private.
    '''
    global _proc_status, _scale
     # get pseudo file  /proc/<pid>/status
    try:
        t = open(_proc_status)
        v = t.read()
        t.close()
    except:
        return 0.0  # non-Linux?
     # get VmKey line e.g. 'VmRSS:  9999  kB\n ...'
    i = v.index(VmKey)
    v = v[i:].split(None, 3)  # whitespace
    if len(v) < 3:
        return 0.0  # invalid format?
     # convert Vm value to bytes
    return float(v[1]) * _scale[v[2]]


def memory(since=0.0):
    '''Return memory usage in bytes.
    '''
    return _VmB('VmSize:') - since


def resident(since=0.0):
    '''Return resident memory usage in bytes.
    '''
    return _VmB('VmRSS:') - since


def stacksize(since=0.0):
    '''Return stack size in bytes.
    '''
    return _VmB('VmStk:') - since

14
Код Windows не работает для меня. Это изменение делает:return int(result[0].WorkingSet)
Джон Фухи

1
Этот код Windows не работает для меня в Windows 7 x64, даже после изменения комментария Джона Фухи.
Basj

У меня есть эта ошибка: вернуть [ wmi_object (obj, instance_of, fields) для obj в self._raw_query (wql)] Файл "C: \ Python27 \ lib \ site-packages \ win32com \ client \ util.py", строка 84, в следующем возвращении _get_good_object_ (self._iter .next (), resultCLSID = self.resultCLSID) pywintypes.com_error: (-2147217385, 'OLE error 0x80041017', None, None), если кто-нибудь может мне помочь? Я выиграл 8 х64, но питон на х32
Раду Влад

Примечание. Я обновил пример Windows, следуя совету Джона Фухи, после проверки (самого последнего) источника модуля wmi. Смотрите также (1) , (2) .
января

33

В Unix вы можете использовать psинструмент для мониторинга:

$ ps u -p 1347 | awk '{sum=sum+$6}; END {print sum/1024}'

где 1347 - некоторый идентификатор процесса. Также результат в МБ.


8

Текущее использование памяти текущего процесса в Linux для Python 2 , Python 3 и pypy без импорта:

def getCurrentMemoryUsage():
    ''' Memory usage in kB '''

    with open('/proc/self/status') as f:
        memusage = f.read().split('VmRSS:')[1].split('\n')[0][:-3]

    return int(memusage.strip())

Он считывает файл состояния текущего процесса, берет все после VmRSS:, затем берет все до первой новой строки (изолируя значение VmRSS) и, наконец, обрезает последние 3 байта, которые являются пробелом и единицей (кБ).
Чтобы вернуться, он удаляет любые пробелы и возвращает его как число.

Протестировано на Linux 4.4 и 4.9, но даже ранняя версия Linux должна работать: просматривая man procи ища информацию о /proc/$PID/statusфайле, она упоминает минимальные версии для некоторых полей (например, Linux 2.6.10 для «VmPTE»), но «VmRSS» Поле (которое я здесь использую) не имеет такого упоминания. Поэтому я предполагаю, что это было там с ранней версии.


5

Мне нравится это , спасибо за @bayer. У меня есть специальный инструмент для подсчета процессов.

# Megabyte.
$ ps aux | grep python | awk '{sum=sum+$6}; END {print sum/1024 " MB"}'
87.9492 MB

# Byte.
$ ps aux | grep python | awk '{sum=sum+$6}; END {print sum " KB"}'
90064 KB

Прикрепить мой список процессов.

$ ps aux  | grep python
root       943  0.0  0.1  53252  9524 ?        Ss   Aug19  52:01 /usr/bin/python /usr/local/bin/beaver -c /etc/beaver/beaver.conf -l /var/log/beaver.log -P /var/run/beaver.pid
root       950  0.6  0.4 299680 34220 ?        Sl   Aug19 568:52 /usr/bin/python /usr/local/bin/beaver -c /etc/beaver/beaver.conf -l /var/log/beaver.log -P /var/run/beaver.pid
root      3803  0.2  0.4 315692 36576 ?        S    12:43   0:54 /usr/bin/python /usr/local/bin/beaver -c /etc/beaver/beaver.conf -l /var/log/beaver.log -P /var/run/beaver.pid
jonny    23325  0.0  0.1  47460  9076 pts/0    S+   17:40   0:00 python
jonny    24651  0.0  0.0  13076   924 pts/4    S+   18:06   0:00 grep python

Ссылка


просто оптимизация кода, чтобы избежать многопотоковостиps aux | awk '/python/{sum+=$6}; END {print sum/1024 " MB"}'
NeronLeVelu

4

Для Python 3.6 и psutil 5.4.5 проще использовать memory_percent()перечисленные здесь функции .

import os
import psutil
process = psutil.Process(os.getpid())
print(process.memory_percent())

1
это требует lib psutil
confiq

4

Еще проще в использовании , чем /proc/self/status: /proc/self/statm. Это просто список разделенных пробелами нескольких статистических данных . Я не смог сказать, присутствуют ли оба файла всегда.

/ Proc / [PID] / statm

Предоставляет информацию об использовании памяти, измеряемую в страницах. Столбцы:

  • size (1) общий размер программы (такой же, как VmSize в / proc / [pid] / status)
  • резидентный (2) размер резидентного набора (такой же, как VmRSS в / proc / [pid] / status)
  • shared (3) количество резидентных общих страниц (т. е. поддержанных файлом) (аналогично RssFile + RssShmem в / proc / [pid] / status)
  • текст (4) текст (код)
  • Библиотека lib (5) (не используется с Linux 2.6; всегда 0)
  • данные (6) данные + стек
  • dt (7) грязные страницы (не используется начиная с Linux 2.6; всегда 0)

Вот простой пример:

from pathlib import Path
from resource import getpagesize

PAGESIZE = getpagesize()
PATH = Path('/proc/self/statm')


def get_resident_set_size() -> int:
    """Return the current resident set size in bytes."""
    # statm columns are: size resident shared text lib data dt
    statm = PATH.read_text()
    fields = statm.split()
    return int(fields[1]) * PAGESIZE


data = []
start_memory = get_resident_set_size()
for _ in range(10):
    data.append('X' * 100000)
    print(get_resident_set_size() - start_memory)

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

0
0
368640
368640
368640
638976
638976
909312
909312
909312

Вы можете видеть, что он увеличивается примерно на 300 000 байтов после примерно 3 распределений по 100 000 байтов.


4

Ниже приведен мой декоратор функций, который позволяет отслеживать, сколько памяти потребляет этот процесс до вызова функции, сколько памяти он использует после вызова функции и как долго выполняется функция.

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.memory_info().rss


def track(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

Итак, когда у вас есть какая-то функция, украшенная этим

from utils import track

@track
def list_create(n):
    print("inside list create")
    return [1] * n

Вы сможете увидеть этот вывод:

inside list create
list_create: memory before: 45,928,448, after: 46,211,072, consumed: 282,624; exec time: 00:00:00

3
import os, win32api, win32con, win32process
han = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION|win32con.PROCESS_VM_READ, 0, os.getpid())
process_memory = int(win32process.GetProcessMemoryInfo(han)['WorkingSetSize'])

7
Это можно улучшить, объяснив, что он делает и как работает.
ArtOfWarfare

2
Исходя из большого числа возвращенных (8 цифр) и того, что я ничего не делаю, я предполагаю, что это должны быть байты? Так что это довольно 28,5 МБ для довольно простаивающего интерактивного экземпляра. (Ух ты ... Я даже не осознавал, что вышеупомянутый комментарий был моим 4 года назад ... это странно.)
ArtOfWarfare

3

Для систем Unix команда time(/ usr / bin / time) выдает эту информацию, если вы передаете -v. Смотрите Maximum resident set sizeниже, который является максимальным (пиковым) реальным (не виртуальным) объемом памяти, который использовался во время выполнения программы :

$ /usr/bin/time -v ls /

    Command being timed: "ls /"
    User time (seconds): 0.00
    System time (seconds): 0.01
    Percent of CPU this job got: 250%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
    Average shared text size (kbytes): 0
    Average unshared data size (kbytes): 0
    Average stack size (kbytes): 0
    Average total size (kbytes): 0
    Maximum resident set size (kbytes): 0
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 315
    Voluntary context switches: 2
    Involuntary context switches: 0
    Swaps: 0
    File system inputs: 0
    File system outputs: 0
    Socket messages sent: 0
    Socket messages received: 0
    Signals delivered: 0
    Page size (bytes): 4096
    Exit status: 0

1
Обратите внимание, что это может не сработать, если вы просто попытаетесь использовать timeвместо /usr/bin/time. Смотрите: askubuntu.com/questions/434289/…
около

1

Использование sh и os, чтобы попасть в ответ python bayer.

float(sh.awk(sh.ps('u','-p',os.getpid()),'{sum=sum+$6}; END {print sum/1024}'))

Ответ в мегабайтах.


4
Следует отметить, что `sh 'не является модулем stdlib. Это можно установить с помощью pip.
Юрген А. Эрхард
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.