Python işlemi tarafından kullanılan toplam bellek?


266

Bir Python programının şu anda ne kadar bellek kullandığını belirlemesinin bir yolu var mı? Tek bir nesne için bellek kullanımı hakkında tartışmalar gördüm, ancak ihtiyacım olan şey, işlem için toplam bellek kullanımıdır, böylece önbelleğe alınmış verileri atmaya başlamanın ne zaman gerekli olduğunu belirleyebilirim.

Yanıtlar:


303

İşte Linux, Windows 7 vb.Dahil olmak üzere çeşitli işletim sistemleri için çalışan kullanışlı bir çözüm:

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

Mevcut Python 2.7 yüklememde psutil 5.6.3 ile son satır

print(process.memory_info()[0])

bunun yerine (API'da bir değişiklik oldu).

Not: pip install psutilhenüz kurulmadıysa yapın.


3
psutilçapraz platformdur ve pskomut satırı aracıyla aynı değerleri döndürebilir : pythonhosted.org/psutil/#psutil.Process.memory_info
amos

1
"( psutil) şu anda Linux, Windows, OSX, FreeBSD ve Sun Solaris'i destekliyor, hem 32 bit hem de 64 bit mimariler, Python sürümleri 2.6'dan 3.4'e kadar" Documentation
Cecilia

2
Bu sayı neden işlem gezginindeki numarayla eşleşmiyor? Psutil'den gelen sayı her zaman yaklaşık% 10 daha büyük gibi görünüyor.
15:42

39
Psutil'in standart kütüphanede olmadığını unutmayın
grisaitis

12
Son sürümleri için psutil, psutil.Process()eşdeğerdir psutil.Process(os.getpid()). Bu, yazmayı hatırlamanız gereken daha az şey.
rnorris

208

Unix tabanlı sistemler için (Linux, Mac OS X, Solaris), getrusage()işlevi standart kütüphane modülünden kullanabilirsiniz resource. Sonuçta ortaya çıkan nesne, çağıran işlem için en yüksek bellek kullanımını ru_maxrsssağlayan özniteliğe sahiptir :

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

Python docs birimlerinin not yapmazlar. man getrusage.2Birimin değer olup olmadığını kontrol etmek için sisteminizin sayfasına bakın . Ubuntu 18.04'te, birim kilobayt olarak not edilir. Mac OS X'te bayttır.

Bu getrusage()işlev ayrıca resource.RUSAGE_CHILDRENalt süreçler için kullanımı ve (bazı sistemlerde) resource.RUSAGE_BOTHtoplam (kendi kendine ve alt) süreç kullanımı için kullanılabilir.

Yalnızca Linux önem veriyorsan alternatif olarak okuyabilir /proc/self/statusveya /proc/self/statmbu soruya ve diğer cevaplar açıklandığı gibi dosya bu onu da.


2
Tamam yapacağım. SO'nun soruları birleştirmek için bir süreci olup olmadığından emin değildim. Yinelenen yayın kısmen insanlara her iki soruda da standart bir kütüphane çözümü olduğunu göstermek içindi ... ve kısmen de temsilci için. ;) Bu yanıtı silmeli miyim?
Nathan Craike

6
Mac OS RSS'yi kesinlikle bayt cinsinden, Linux ise kilobayt olarak döndürür.
Neil

13
Birimler kilobayt olarak DEĞİLDİR. Platforma bağımlıdır, bu yüzden bulmak için resource.getpagesize () kullanmanız gerekir. Verilen Python belgeleri ( docs.python.org/2/library/resource.html#resource-usage ) bu konuda çok açıktır. Kutumda 4096 var.
Ben Lin

5
@BenLin Bu Python belgeleri açıkça yanlış veya Mac sürümünde bir hata var. Getrusage tarafından kullanılan birim ve getpagesize tarafından döndürülen değer kesinlikle farklıdır.
Andrew

6
Mevcut kullanım için sorulan soru . Bunun maksimum kullanım olduğunu unutmayın . (Yine de yararlı bir cevap, sadece yanlışlıkla kopyalayıp yapıştıran insanları uyarıyor.)
Luc

65

Windows'ta WMI'yı kullanabilirsiniz ( ana sayfa , peynir dükkanı ):


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'ta (python yemek kitabından 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 kodu benim için çalışmıyor. Bu değişiklik:return int(result[0].WorkingSet)
John Fouhy

1
Bu Windows kodu, John Fouhy'nin yorum değişikliğinden sonra bile Windows 7 x64'te benim için çalışmıyor.
Basj

Bu hatayı aldım: self._raw_query (wql)] obj dosyasındaki obj için return [ wmi_object (obj, instance_of, fields)] Dosya C: \ Python27 \ lib \ site-paketleri \ win32com \ client \ util.py ", satır 84, bir sonraki dönüşte _get_good_object_ (self._iter .next (), sonuçCLSID = self.resultCLSID) pywintypes.com_error: (-2147217385, 'OLE hatası 0x80041017', Yok, Hiçbiri) biri bana yardımcı olabilirse? 8 x64 kazandım ama x32'de python aldım
Radu Vlad

Not: Wmi modülünün (en son) kaynağını inceledikten sonra John Fouhy'nin önerisini izleyen Windows örneğini güncelledim. Ayrıca bkz. (1) , (2) .
jedwards

33

Unix'te, psaracı izlemek için kullanabilirsiniz:

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

burada 1347 bir işlem kimliğidir. Ayrıca, sonuç MB cinsindendir.


8

Python 2 , Python 3 ve pypy için Linux'ta geçerli işlemin herhangi bir içe aktarılmadan geçerli bellek kullanımı :

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())

Geçerli işlemin durum dosyasını okur, her şeyi alır VmRSS:, sonra her şeyi ilk satırdan önce alır (VmRSS'nin değerini izole eder) ve son olarak boşluk ve birim (kB) olan son 3 baytı keser.
Geri dönmek için, tüm boşlukları çıkarır ve sayı olarak döndürür.

Linux 4.4 ve 4.9 üzerinde test edilmiştir, ancak erken bir Linux sürümü bile çalışmalıdır: dosyadaki man procbilgileri aramak ve aramak /proc/$PID/status, bazı alanlar için minimum sürümlerden ("VmPTE" için Linux 2.6.10 gibi), ancak "VmRSS'den bahseder. "(burada kullandığım) alanın böyle bir sözü yok. Bu nedenle, erken bir versiyondan beri orada olduğunu varsayıyorum.


5

Sevdiğim o , @bayer için teşekkür ederim. Şimdi belirli bir işlem sayım aracı alıyorum.

# 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

İşlem listemi ekle.

$ 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

Referans


borudan kaçınmak için sadece bir kod optimizasyonups aux | awk '/python/{sum+=$6}; END {print sum/1024 " MB"}'
NeronLeVelu

4

Python 3.6 ve psutil 5.4.5 için buradamemory_percent() listelenen işlevi kullanmak daha kolaydır .

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

1
bu lib psutil gerektirir
confiq

4

Hatta daha kolay kullanmak /proc/self/status: /proc/self/statm. Bu sadece birkaç istatistikin alanla sınırlı bir listesidir . Her iki dosyanın da her zaman mevcut olup olmadığını söyleyemedim.

/ Proc / [PID] / statm

Sayfalarda ölçülen bellek kullanımı hakkında bilgi sağlar. Sütunlar:

  • boyut (1) toplam program boyutu (/ proc / [pid] / durumundaki VmSize ile aynı)
  • yerleşik (2) yerleşik set boyutu (/ proc / [pid] / durumundaki VmRSS ile aynı)
  • paylaşılan (3) yerleşik paylaşılan sayfa sayısı (yani bir dosya tarafından desteklenir) (/ proc / [pid] / status içindeki RssFile + RssShmem ile aynı)
  • metin (4) metin (kod)
  • lib (5) kitaplığı (Linux 2.6'dan beri kullanılmamaktadır; her zaman 0)
  • veri (6) veri + yığın
  • dt (7) kirli sayfalar (Linux 2.6'dan beri kullanılmıyor; her zaman 0)

İşte basit bir örnek:

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)

Bu şuna benzer bir liste üretir:

0
0
368640
368640
368640
638976
638976
909312
909312
909312

Yaklaşık 100.000 baytlık 3 ayırmadan sonra yaklaşık 300.000 bayt atladığını görebilirsiniz.


4

Aşağıda, işlev çağrısından önce bu işlemin ne kadar bellek harcadığını, işlev çağrısından sonra ne kadar bellek kullandığını ve işlevin ne kadar süreyle yürütüldüğünü takip etmeyi sağlayan işlev dekoratörüm.

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

Yani, onunla süslenmiş bir fonksiyonunuz olduğunda

from utils import track

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

Bu çıktıyı görebileceksiniz:

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
Bu, ne yaptığına ve nasıl çalıştığına dair bazı açıklamalarla geliştirilebilir.
ArtOfWarfare

2
Döndürülen çok sayıda (8 basamaklı) ve nasıl bir şey yapmıyorum, bunun bayt olması gerektiğini tahmin ediyorum? Bu nedenle, oldukça boş bir etkileşimli örnek için yaklaşık 28.5 MB. (Vay ... Yukarıdaki yorumun 4 yıl öncesinden benim olduğumu bile bilmiyordum ... bu garip.)
ArtOfWarfare

3

Unix sistemleri için komut time(/ usr / bin / time) -v'yi geçerseniz bu bilgiyi verir. Program yürütme sırasında kullanılan maksimum (en yüksek) gerçek (sanal olmayan) bellekMaximum resident set size olan aşağıya bakın :

$ /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
timeBunun yerine kullanmayı denerseniz bunun başarısız olabileceğini unutmayın /usr/bin/time. Bakınız: askubuntu.com/questions/434289/…
abought

1

Python bayer'in cevabına girmek için sh ve os komutlarını kullanma.

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

Cevap megabayt cinsindendir.


4
"Sh" nin bir stdlib modülü olmadığı unutulmamalıdır. Yine de pip ile kurulabilir.
Jürgen A. Erhard
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.