Загальна пам'ять, яка використовується процесом 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 відсутній у стандартній бібліотеці
грисаїт

12
Для останніх версій psutil, що psutil.Process()еквівалентно psutil.Process(os.getpid()). Це одна річ, яку потрібно пам’ятати, щоб набрати.
rnorris

208

Для систем на базі 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, безумовно, відрізняються.
Андрій

6
Питання задали поточне використання. Зауважте, що це максимальне використання. (Все ще корисна відповідь. Просто попереджаю людей, які помилково копіюють її та вставляють.)
Люк

65

У Windows можна використовувати WMI ( домашня сторінка , сирник ):


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, навіть після зміни коментарів Джона Фузі.
Бась

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

Примітка: Я оновив приклад Windows за пропозицією Джона Фузі після огляду (останнього) джерела модуля wmi. Див. Також (1) , (2) .
jedwards

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

Надає інформацію про використання пам'яті, виміряну на сторінках. Стовпці:

  • розмір (1) загальний розмір програми (такий же, як VmSize в / proc / [pid] / status)
  • розмір набору резидента (2) (такий же, як VmRSS в / proc / [pid] / status)
  • спільна (3) кількість резидентних спільних сторінок (тобто, підкріплених файлом) (те саме, що RssFile + RssShmem в / proc / [pid] / status)
  • текст (4) текст (код)
  • бібліотека lib (5) (не використовується з Linux 2.6; завжди 0)
  • data (6) data + стек
  • 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, щоб потрапити у відповідь пітона байєра.

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.