Отслеживание * максимального * использования памяти функцией Python - PullRequest
38 голосов
/ 24 марта 2012

Я хочу узнать, каков максимальный объем ОЗУ, выделяемый во время вызова функции (в Python). Есть другие вопросы по SO, связанные с отслеживанием использования оперативной памяти:

Какой профилировщик памяти Python рекомендуется?

Как мне профилировать использование памяти в Python?

но, похоже, они позволяют вам больше отслеживать использование памяти во время вызова метода heap() (в случае с гуппи). Тем не менее, я хочу отследить функцию во внешней библиотеке, которую я не могу изменить, и которая начинает использовать много оперативной памяти, но затем освобождает ее после завершения выполнения функции. Есть ли способ узнать, какой общий объем оперативной памяти использовался во время вызова функции?

Ответы [ 6 ]

25 голосов
/ 12 апреля 2012

Этот вопрос показался мне довольно интересным, и он дал мне повод заглянуть в Гуппи / Хипи, за что я благодарю вас.

Я пытался около 2 часов заставить Хипи следить за вызовом / процессом функции без изменения его источника с ноль удачей.

Я нашел способ выполнить вашу задачу, используя встроенную библиотеку Python resource.Обратите внимание, что в документации не указано, что возвращает значение RU_MAXRSS.Другой пользователь SO отметил , что он был в кБ.Запуская Mac OSX 7.3 и наблюдая, как мои системные ресурсы увеличиваются во время тестового кода ниже, я считаю, что возвращаемые значения находятся в байтах , а не в килобайтах.

10000-футовое представление о том, как я использовал библиотеку resource для мониторинга вызова библиотеки, заключалось в запуске функции в отдельном (контролируемом) потоке и отслеживании системных ресурсов для этого процесса в главном потоке.Ниже у меня есть два файла, которые вам нужно запустить, чтобы протестировать его.

Монитор ресурсов библиотеки - what_you_want.py

import resource
import time

from stoppable_thread import StoppableThread


class MyLibrarySniffingClass(StoppableThread):
    def __init__(self, target_lib_call, arg1, arg2):
        super(MyLibrarySniffingClass, self).__init__()
        self.target_function = target_lib_call
        self.arg1 = arg1
        self.arg2 = arg2
        self.results = None

    def startup(self):
        # Overload the startup function
        print "Calling the Target Library Function..."

    def cleanup(self):
        # Overload the cleanup function
        print "Library Call Complete"

    def mainloop(self):
        # Start the library Call
        self.results = self.target_function(self.arg1, self.arg2)

        # Kill the thread when complete
        self.stop()

def SomeLongRunningLibraryCall(arg1, arg2):
    max_dict_entries = 2500
    delay_per_entry = .005

    some_large_dictionary = {}
    dict_entry_count = 0

    while(1):
        time.sleep(delay_per_entry)
        dict_entry_count += 1
        some_large_dictionary[dict_entry_count]=range(10000)

        if len(some_large_dictionary) > max_dict_entries:
            break

    print arg1 + " " +  arg2
    return "Good Bye World"

if __name__ == "__main__":
    # Lib Testing Code
    mythread = MyLibrarySniffingClass(SomeLongRunningLibraryCall, "Hello", "World")
    mythread.start()

    start_mem = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
    delta_mem = 0
    max_memory = 0
    memory_usage_refresh = .005 # Seconds

    while(1):
        time.sleep(memory_usage_refresh)
        delta_mem = (resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) - start_mem
        if delta_mem > max_memory:
            max_memory = delta_mem

        # Uncomment this line to see the memory usuage during run-time 
        # print "Memory Usage During Call: %d MB" % (delta_mem / 1000000.0)

        # Check to see if the library call is complete
        if mythread.isShutdown():
            print mythread.results
            break;

    print "\nMAX Memory Usage in MB: " + str(round(max_memory / 1000.0, 3))

Остановимая нить - stoppable_thread.py

import threading
import time

class StoppableThread(threading.Thread):
    def __init__(self):
        super(StoppableThread, self).__init__()
        self.daemon = True
        self.__monitor = threading.Event()
        self.__monitor.set()
        self.__has_shutdown = False

    def run(self):
        '''Overloads the threading.Thread.run'''
        # Call the User's Startup functions
        self.startup()

        # Loop until the thread is stopped
        while self.isRunning():
            self.mainloop()

        # Clean up
        self.cleanup()

        # Flag to the outside world that the thread has exited
        # AND that the cleanup is complete
        self.__has_shutdown = True

    def stop(self):
        self.__monitor.clear()

    def isRunning(self):
        return self.__monitor.isSet()

    def isShutdown(self):
        return self.__has_shutdown


    ###############################
    ### User Defined Functions ####
    ###############################

    def mainloop(self):
        '''
        Expected to be overwritten in a subclass!!
        Note that Stoppable while(1) is handled in the built in "run".
        '''
        pass

    def startup(self):
        '''Expected to be overwritten in a subclass!!'''
        pass

    def cleanup(self):
        '''Expected to be overwritten in a subclass!!'''
        pass
19 голосов
/ 28 марта 2013

Это можно сделать с помощью memory_profiler .Функция memory_usage возвращает список значений, которые представляют использование памяти с течением времени (по умолчанию для кусков 0,1 секунды).Если вам нужен максимум, просто возьмите максимум из этого списка.Маленький пример:

from memory_profiler import memory_usage
from time import sleep

def f():
    # a function that with growing
    # memory consumption
    a = [0] * 1000
    sleep(.1)
    b = a * 100
    sleep(.1)
    c = b * 100
    return a

mem_usage = memory_usage(f)
print('Memory usage (in chunks of .1 seconds): %s' % mem_usage)
print('Maximum memory usage: %s' % max(mem_usage))

В моем случае (memory_profiler 0.25) if выводит следующий вывод:

Memory usage (in chunks of .1 seconds): [45.65625, 45.734375, 46.41015625, 53.734375]
Maximum memory usage: 53.734375
5 голосов
/ 04 октября 2014

Похоже, что работает под Windows. Не знаю о других операционных системах.

In [50]: import os

In [51]: import psutil

In [52]: process = psutil.Process(os.getpid())

In [53]: process.get_ext_memory_info().peak_wset
Out[53]: 41934848
2 голосов
/ 19 июня 2017

Вы можете использовать ресурс библиотеки Python для получения использования памяти.

import resource
resource.getrusage(resource.RUSAGE_SELF).ru_maxrss

Это даст использование памяти в килобайтах, для преобразования в МБ, деленное на 1000.

0 голосов
/ 24 октября 2018

Стандартная утилита Unix time отслеживает максимальное использование памяти процессом, а также другую полезную статистику для вашей программы.

Пример вывода (maxresident - максимальное использование памяти, в килобайтах.):

> time python ./scalabilty_test.py
45.31user 1.86system 0:47.23elapsed 99%CPU (0avgtext+0avgdata 369824maxresident)k
0inputs+100208outputs (0major+99494minor)pagefaults 0swaps
0 голосов
/ 16 октября 2016

С этой задачей тоже боролись. После экспериментов с psutil и методами от Адама я написал функцию (благодарность Адаму Льюису) для измерения памяти, используемой определенной функцией. Людям легче найти и использовать.

1) measure_memory_usage

2) test measure_memory_usage

Я обнаружил, что материалы о многопоточности и переопределении суперкласса действительно помогают понять, что Адам делает в своих сценариях. Извините, я не могу опубликовать ссылки из-за максимального ограничения "2 ссылки".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...