Tổng bộ nhớ được sử dụng bởi quá trình Python?


266

Có cách nào để chương trình Python xác định dung lượng bộ nhớ hiện đang sử dụng không? Tôi đã thấy các cuộc thảo luận về việc sử dụng bộ nhớ cho một đối tượng, nhưng điều tôi cần là tổng mức sử dụng bộ nhớ cho quá trình, để tôi có thể xác định khi nào cần thiết để bắt đầu loại bỏ dữ liệu được lưu trong bộ nhớ cache.

Câu trả lời:


303

Đây là một giải pháp hữu ích hoạt động cho các hệ điều hành khác nhau, bao gồm Linux, Windows 7, v.v.:

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

Trên bản cài đặt Python 2.7 hiện tại của tôi với psutil 5.6.3, dòng cuối cùng phải là

print(process.memory_info()[0])

thay vào đó (đã có một sự thay đổi trong API).

Lưu ý: làm pip install psutilnếu nó chưa được cài đặt.


3
psutillà nền tảng chéo và có thể trở lại các giá trị tương tự như các pscông cụ dòng lệnh: pythonhosted.org/psutil/#psutil.Process.memory_info
amos

1
"( psutil) Hiện hỗ trợ Linux, Windows, OSX, FreeBSD và Sun Solaris, cả kiến ​​trúc 32 bit và 64 bit, với các phiên bản Python từ 2.6 đến 3.4" từ Tài liệu
Cecilia

2
Tại sao con số này không khớp với số trong trình thám hiểm quy trình? Con số từ psutil dường như luôn lớn hơn khoảng 10%.
lời giới thiệu

39
Lưu ý rằng psutil không có trong thư viện chuẩn
viêm grisa

12
Đối với các phiên bản gần đây của psutil, psutil.Process()tương đương với psutil.Process(os.getpid()). Đó là một điều ít bạn cần nhớ để gõ.
rnorris

208

Đối với các hệ thống dựa trên Unix (Linux, Mac OS X, Solaris), bạn có thể sử dụng getrusage()chức năng từ mô-đun thư viện tiêu chuẩn resource. Đối tượng kết quả có thuộc tính ru_maxrss, cung cấp mức sử dụng bộ nhớ cao nhất cho quá trình gọi:

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

Các tài liệu Python không ghi chú các đơn vị. Tham khảo trang hệ thống cụ thể của bạn man getrusage.2để kiểm tra đơn vị cho giá trị. Trên Ubuntu 18.04, đơn vị được ghi chú là kilobyte. Trên Mac OS X, đó là byte.

Các getrusage()chức năng cũng có thể được đưa ra resource.RUSAGE_CHILDRENđể có được sử dụng cho các quá trình đứa trẻ, và (trên một số hệ thống)resource.RUSAGE_BOTH cho tổng (bản thân và trẻ em) sử dụng quá trình.

Nếu bạn chỉ quan tâm đến Linux, bạn có thể thay thế đọc /proc/self/statushoặc /proc/self/statmtệp như được mô tả trong các câu trả lời khác cho câu hỏi này và câu hỏi này cũng vậy.


2
Được rồi, sẽ làm. Tôi không chắc liệu SO có một quy trình để hợp nhất các câu hỏi hay không. Bài đăng trùng lặp là một phần để cho mọi người thấy có một giải pháp thư viện chuẩn cho cả hai câu hỏi ... và một phần cho đại diện. ;) Tôi có nên xóa câu trả lời này?
Nathan Craike

6
Mac OS chắc chắn trả về RSS theo byte, Linux trả về bằng kilobyte.
Neil

13
Các đơn vị KHÔNG tính bằng kilobyte. Nó phụ thuộc vào nền tảng, vì vậy bạn phải sử dụng resource.getpagesize () để tìm hiểu. Các tài liệu Python đã cho ( docs.python.org/2/l Library / resource.html # resource-usage ) thực sự rất rõ ràng về nó. Nó là 4096 trong hộp của tôi.
Ben Lin

5
@BenLin Những tài liệu Python đó rõ ràng sai hoặc có lỗi trên phiên bản Mac. Đơn vị được sử dụng bởi getrusage và giá trị được trả về bởi getpagesize hoàn toàn khác nhau.
Andrew

6
Câu hỏi yêu cầu sử dụng hiện tại . Lưu ý rằng đây là sử dụng tối đa . (Vẫn là một câu trả lời hữu ích, chỉ cảnh báo những người sao chép nhầm và dán nó.)
Luc

65

Trên Windows, bạn có thể sử dụng WMI ( trang chủ , 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)

Trên Linux (từ sách dạy nấu ăn 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
Mã Windows không hoạt động đối với tôi. Thay đổi này có:return int(result[0].WorkingSet)
John Fouhy

1
Mã Windows này không hoạt động với tôi trên Windows 7 x64, ngay cả sau khi sửa đổi nhận xét của John Fouhy.
Basj

Tôi gặp lỗi này: return [ wmi_object (obj, instance_of, các trường) cho obj trong self._raw_query (wql)] Tệp "C: \ Python27 \ lib \ site-gói \ win32com \ client \ produc.py", dòng 84, trong lần trả lại tiếp theo _get_good_object_ (self._iter .next (), resultCLSID = self.resultCLSID) pywintypes.com_error: (-2147217385, 'Lỗi OLE 0x80041017', Không ai, Không ai) Tôi đã thắng 8 x64 nhưng trăn trên x32
Radu Vlad

Lưu ý: Tôi đã cập nhật ví dụ về cửa sổ theo đề xuất của John Fouhy sau khi kiểm tra nguồn (mới nhất) của mô-đun wmi. Xem thêm (1) , (2) .
jedwards 17/03/2016

33

Trên unix, bạn có thể sử dụng pscông cụ để theo dõi nó:

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

trong đó 1347 là một số id quá trình. Ngoài ra, kết quả là MB.


8

Việc sử dụng bộ nhớ hiện tại của quy trình hiện tại trên Linux , cho Python 2 , Python 3pypy mà không cần nhập bất kỳ:

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

Nó đọc tệp trạng thái của quy trình hiện tại, lấy mọi thứ sau VmRSS:, sau đó lấy mọi thứ trước dòng mới đầu tiên (cô lập giá trị của VmRSS) và cuối cùng cắt bỏ 3 byte cuối cùng là khoảng trắng và đơn vị (kB).
Để trả về, nó tước bất kỳ khoảng trắng nào và trả về dưới dạng số.

Đã thử nghiệm trên Linux 4.4 và 4.9, nhưng ngay cả phiên bản Linux đầu tiên cũng hoạt động: tìm kiếm man procvà tìm kiếm thông tin trên /proc/$PID/statustệp, nó đề cập đến các phiên bản tối thiểu cho một số trường (như Linux 2.6.10 cho "VmPTE"), nhưng "VmRSS "Trường (mà tôi sử dụng ở đây) không có đề cập như vậy. Vì vậy, tôi cho rằng nó đã ở đó từ phiên bản đầu tiên.


5

Tôi thích , cảm ơn bạn vì @bayer. Bây giờ tôi có một công cụ đếm quy trình cụ thể.

# 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

Đính kèm danh sách quá trình của tôi.

$ 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

Tài liệu tham khảo


chỉ cần tối ưu hóa mã để tránh đa ốngps aux | awk '/python/{sum+=$6}; END {print sum/1024 " MB"}'
NeronLeVelu

4

Đối với Python 3.6 và psutil 5.4.5, việc sử dụng memory_percent()chức năng được liệt kê ở đây dễ dàng hơn .

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

1
điều này đòi hỏi lib psutil
confiq

4

Thậm chí dễ sử dụng hơn /proc/self/status: /proc/self/statm. Nó chỉ là một danh sách giới hạn không gian của một số thống kê . Tôi đã không thể biết nếu cả hai tập tin luôn luôn có mặt.

/ Proc / [pid] / statm

Cung cấp thông tin về việc sử dụng bộ nhớ, được đo bằng các trang. Các cột là:

  • kích thước (1) tổng kích thước chương trình (giống như VmSize in / Proc / [pid] / status)
  • kích thước tập hợp cư dân (2) (giống như VmRSS trong / Proc / [pid] / status)
  • đã chia sẻ (3) số trang chia sẻ thường trú (nghĩa là được hỗ trợ bởi một tệp) (giống như RssFile + RssShmem trong / Proc / [pid] / status)
  • văn bản (4) văn bản (mã)
  • thư viện lib (5) (không được sử dụng kể từ Linux 2.6; luôn là 0)
  • dữ liệu (6) dữ liệu + ngăn xếp
  • dt (7) trang bẩn (không được sử dụng kể từ Linux 2.6; luôn là 0)

Đây là một ví dụ đơn giản:

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)

Điều đó tạo ra một danh sách trông giống như thế này:

0
0
368640
368640
368640
638976
638976
909312
909312
909312

Bạn có thể thấy rằng nó nhảy khoảng 300.000 byte sau khoảng 3 lần phân bổ 100.000 byte.


4

Dưới đây là trình trang trí chức năng của tôi cho phép theo dõi quá trình này tiêu thụ bao nhiêu bộ nhớ trước khi gọi hàm, bao nhiêu bộ nhớ sử dụng sau khi gọi hàm và thời gian thực hiện chức năng.

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

Vì vậy, khi bạn có một số chức năng trang trí với nó

from utils import track

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

Bạn sẽ có thể thấy đầu ra này:

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
Điều này có thể được cải thiện với một số giải thích về những gì nó làm và cách thức hoạt động.
ArtOfWarfare

2
Dựa trên số lượng lớn được trả về (8 chữ số) và cách tôi không làm gì nhiều, tôi đoán đây có phải là byte không? Vì vậy, đó là khoảng 28,5 MB cho một ví dụ tương tác khá nhàn rỗi. (Wow ... Tôi thậm chí không nhận ra nhận xét trên là của tôi từ 4 năm trước ... thật kỳ lạ.)
ArtOfWarfare

3

Đối với lệnh hệ thống Unix time(/ usr / bin / time) cung cấp cho bạn thông tin đó nếu bạn vượt qua -v. Xem Maximum resident set sizedưới đây, đó là tối đa (đỉnh) thực (không ảo) bộ nhớ đã được sử dụng trong quá trình thực hiện chương trình :

$ /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
Lưu ý rằng điều này có thể thất bại nếu bạn chỉ cố gắng sử dụng timethay vì /usr/bin/time. Xem: askubuntu.com/questions/434289/...
abought

1

Sử dụng sh và os để đi vào câu trả lời của python bay.

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

Câu trả lời là bằng megabyte.


4
Cần lưu ý rằng `sh 'không phải là mô-đun stdlib. Nó có thể cài đặt với pip, mặc dù.
Jürgen A. Erhard
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.