Pythonã¯æžãããã匷åãªèšèªã§ãããç¹ã«å€§èŠæš¡ãªããŒã¿åŠçãé·æé皌åããã¢ããªã±ãŒã·ã§ã³ã§ã¯ãã¡ã¢ãªäœ¿çšéãåé¡ã«ãªãããšããããŸããããªããããã°ã©ã ãé
ããªâŠãããã€ã®éã«ãã¡ã¢ãªã䜿ããããŠããâŠïŒããšæããããšã¯ãããŸãããïŒ ð€
ãããªæã«åœ¹ç«ã€ã®ããPythonã®ã¡ã¢ãªãããã¡ã€ãªã³ã°ã©ã€ãã©ãª memory_profiler
ã§ãã
ãã®ããã°èšäºã§ã¯ãmemory_profiler
ã®åºæ¬çãªäœ¿ãæ¹ããå¿çšçãªæ©èœãŸã§ãå
·äœçãªã³ãŒãäŸã亀ããªãã詳ãã解説ããŸããã¡ã¢ãªã®æåãç解ããããå¹ççãªPythonã³ãŒããæžãããã®ç¬¬äžæ©ãèžã¿åºããŸãããïŒ
memory_profiler ãšã¯ïŒ
memory_profiler
ã¯ãPythonããã°ã©ã ã®ã¡ã¢ãªæ¶è²»éãç£èŠã»åæããããã®ã©ã€ãã©ãªã§ããäž»ã«ä»¥äžã®æ©èœãæäŸããŸãã
- è¡ããšã®ã¡ã¢ãªäœ¿çšéåæ: é¢æ°å ã®åè¡ãå®è¡ãããåŸã®ã¡ã¢ãªäœ¿çšéãšããã®è¡ã§ã®ã¡ã¢ãªå¢å éãèšæž¬ããŸããããã«ãããã©ã®ã³ãŒãè¡ãã¡ã¢ãªãå€ãæ¶è²»ããŠããããç¹å®ã§ããŸãã
- æç³»åã§ã®ã¡ã¢ãªäœ¿çšéç£èŠ: ããã°ã©ã å®è¡äžã®ã¡ã¢ãªäœ¿çšéã®æšç§»ãèšé²ããã°ã©ããšããŠå¯èŠåã§ããŸããã¡ã¢ãªãªãŒã¯ã®çºèŠãªã©ã«åœ¹ç«ã¡ãŸãã
- ã·ã³ãã«ãªå°å
¥:
@profile
ãã³ã¬ãŒã¿ãé¢æ°ã«è¿œå ããã ãã§ãåºæ¬çãªãããã¡ã€ãªã³ã°ãéå§ã§ããŸãã - Jupyter/IPythoné£æº: ããžãã¯ã³ãã³ãã䜿ã£ãŠãJupyter NotebookãIPythonç°å¢ã§æ軜ã«ã¡ã¢ãªäœ¿çšéã枬å®ã§ããŸãã
ãã®ã©ã€ãã©ãªã¯çŽç²ãªPythonã§æžãããŠãããå
éšã§ psutil
ã©ã€ãã©ãªãå©çšããŠããã»ã¹ã®ã¡ã¢ãªæ
å ±ãååŸããŠããŸãã
memory_profiler
ã¯çŸåšæŽ»çºã«ã¯ã¡ã³ããã³ã¹ãããŠããªãããã§ãThis package is no longer actively maintained.” ãšã®èšèŒããïŒãããããäŸç¶ãšããŠå€ãã®ãããžã§ã¯ãã§å©çšãããŠãããåºæ¬çãªã¡ã¢ãªãããã¡ã€ãªã³ã°ã«ã¯åå圹ç«ã¡ãŸãã代æ¿ããŒã«ãšããŠã¯ Memray ã Fil ãªã©ãååšããŸãã
ã€ã³ã¹ããŒã«æ¹æ³ ð»
memory_profiler
ã®ã€ã³ã¹ããŒã«ã¯ pip ã䜿ã£ãŠç°¡åã«è¡ããŸããäŸåã©ã€ãã©ãªã§ãã psutil
ãäžç·ã«ã€ã³ã¹ããŒã«ãããŸãã
pip install -U memory_profiler
ãŸããæç³»åã°ã©ãã®æç»æ©èœïŒåŸè¿°ãã mprof plot
ïŒã䜿çšããå Žåã¯ãmatplotlib
ãå¿
èŠã«ãªããŸããå¿
èŠã«å¿ããŠã€ã³ã¹ããŒã«ããŠãã ããã
pip install matplotlib
conda (conda-forge) ã䜿çšããŠããå Žåãã€ã³ã¹ããŒã«å¯èœã§ãã
conda install -c conda-forge memory_profiler
åºæ¬çãªäœ¿ãæ¹: è¡ããšã®ã¡ã¢ãªãããã¡ã€ãªã³ã°
æãåºæ¬çãªäœ¿ãæ¹ã¯ãã¡ã¢ãªäœ¿çšéãèšæž¬ãããé¢æ°ã« @profile
ãã³ã¬ãŒã¿ãè¿œå ããããšã§ããline_profiler
ã©ã€ãã©ãªã䜿ã£ãããšãããæ¹ã¯ãåæ§ã®æèŠã§å©çšã§ããŸãã
äŸãšããŠã倧ããªãªã¹ããäœæã»åé€ããç°¡åãªé¢æ°ããããã¡ã€ãªã³ã°ããŠã¿ãŸãããã
sample_script.py:
from memory_profiler import profile
@profile
def create_large_list():
print("é¢æ°éå§")
a = [1] * (10 ** 6) # 100äžèŠçŽ ã®ãªã¹ããäœæ
print("ãªã¹ãaäœæå®äº")
b = [2] * (2 * 10 ** 7) # 2000äžèŠçŽ ã®ãªã¹ããäœæ
print("ãªã¹ãbäœæå®äº")
del b # ãªã¹ãbãåé€
print("ãªã¹ãbåé€å®äº")
return a
if __name__ == '__main__':
print("ã¹ã¯ãªããéå§")
result = create_large_list()
print("ã¹ã¯ãªããçµäº")
ãã®ã¹ã¯ãªãããå®è¡ããã«ã¯ãéåžžã® python sample_script.py
ã§ã¯ãªãã-m memory_profiler
ãªãã·ã§ã³ãä»ã㊠Python ã€ã³ã¿ãŒããªã¿ãèµ·åããŸãã
python -m memory_profiler sample_script.py
å®è¡ãããšãæšæºåºåã«ä»¥äžã®ãããªãããã¡ã€ãªã³ã°çµæã衚瀺ãããŸã (å€ã¯ç°å¢ã«ãã£ãŠç°ãªããŸã)ã
ã¹ã¯ãªããéå§
é¢æ°éå§
ãªã¹ãaäœæå®äº
ãªã¹ãbäœæå®äº
ãªã¹ãbåé€å®äº
ã¹ã¯ãªããçµäº
Filename: sample_script.py
Line # Mem usage Increment Occurrences Line Contents
=============================================================
3 53.0 MiB 53.0 MiB 1 @profile
4 def create_large_list():
5 53.0 MiB 0.0 MiB 1 print("é¢æ°éå§")
6 60.6 MiB 7.6 MiB 1 a = [1] * (10 ** 6) # 100äžèŠçŽ ã®ãªã¹ããäœæ
7 60.6 MiB 0.0 MiB 1 print("ãªã¹ãaäœæå®äº")
8 213.1 MiB 152.5 MiB 1 b = [2] * (2 * 10 ** 7) # 2000äžèŠçŽ ã®ãªã¹ããäœæ
9 213.1 MiB 0.0 MiB 1 print("ãªã¹ãbäœæå®äº")
10 60.6 MiB -152.5 MiB 1 del b # ãªã¹ãbãåé€
11 60.6 MiB 0.0 MiB 1 print("ãªã¹ãbåé€å®äº")
12 60.6 MiB 0.0 MiB 1 return a
åºåçµæã®èŠæ¹
åå | 説æ |
---|---|
Line # |
ãããã¡ã€ãªã³ã°å¯Ÿè±¡ã®ã³ãŒãè¡çªå· |
Mem usage |
ãã®è¡ã®å®è¡åŸã®Pythonã€ã³ã¿ããªã¿ã®ç·ã¡ã¢ãªäœ¿çšé (MiB: Mebibyte) |
Increment |
åã®è¡ããã®ã¡ã¢ãªäœ¿çšéã®å¢æž |
Occurrences |
ãã®è¡ãå®è¡ãããåæ° (ã«ãŒããªã©ã§è€æ°åå®è¡ãããå Žåã«å¢å ) |
Line Contents |
ãããã¡ã€ãªã³ã°å¯Ÿè±¡ã®ã³ãŒãè¡ã®å 容 |
ãã®çµæããã8è¡ç®ã® b = [2] * (2 * 10 ** 7)
ã§ã¡ã¢ãªäœ¿çšéãçŽ 152.5 MiB å¢å ãã10è¡ç®ã® del b
ã§ãã®ã¡ã¢ãªã解æŸãããŠããããšãããããŸãããã®ããã«ãã©ã®è¡ã§ã¡ã¢ãªãå€ã確ä¿ã»è§£æŸãããŠããããå
·äœçã«ææ¡ã§ããŸããð
@profile
ãã³ã¬ãŒã¿ã¯ãèšæž¬ãããé¢æ°ã«ã®ã¿ä»äžããŸããè€æ°ã®é¢æ°ã«ä»äžããããšãå¯èœã§ãã
@profile(stream=f)
ã®ããã«ããã¡ã€ã«ãªããžã§ã¯ãã stream
åŒæ°ã«æž¡ãããšãã§ããŸãã
import io
from memory_profiler import profile
output_log = io.StringIO() # ãŸã㯠open('memory_log.txt', 'w+')
@profile(stream=output_log)
def some_function():
# ... åŠç ...
pass
if __name__ == '__main__':
some_function()
print(output_log.getvalue()) # å
容ã確èª
# output_log.close() # ãã¡ã€ã«ã®å Žåã¯éãã
å¿çšçãªäœ¿ãæ¹
1. æç³»åã§ã®ã¡ã¢ãªäœ¿çšéç£èŠ (`mprof`) ð
memory_profiler
ã«ã¯ mprof
ãšããã³ãã³ãã©ã€ã³ããŒã«ãä»å±ããŠãããããã°ã©ã å®è¡äžã®ã¡ã¢ãªäœ¿çšéã®å€åãèšé²ããã°ã©ããšããŠããããããããšãã§ããŸããããã¯ãã¡ã¢ãªãªãŒã¯ã®èª¿æ»ããæéçµéã«äŒŽãã¡ã¢ãªãã¿ãŒã³ã®ææ¡ã«éåžžã«äŸ¿å©ã§ãã
ãŸããmprof run
ã³ãã³ãã§å¯Ÿè±¡ã®ã¹ã¯ãªãããå®è¡ããŸãããã®éãã¹ã¯ãªããå
ã® @profile
ãã³ã¬ãŒã¿ã¯äžèŠã§ãïŒããããfrom memory_profiler import profile
ã®ã€ã³ããŒãããããšãmprof run
ãããŸãåäœããªãå ŽåããããŸãïŒã
mprof run sample_script.py
å®è¡ãããšãã«ã¬ã³ããã£ã¬ã¯ããªã« mprofile_<timestamp>.dat
ãšãã圢åŒã®ããŒã¿ãã¡ã€ã«ãçæãããŸãããã®ãã¡ã€ã«ã«æç³»åã®ã¡ã¢ãªäœ¿çšéããŒã¿ãèšé²ãããŠããŸãã
次ã«ãmprof plot
ã³ãã³ãã§èšé²ãããããŒã¿ãã°ã©ãåããŸããããã©ã«ãã§ã¯æåŸã«çæããã .dat
ãã¡ã€ã«ã䜿çšãããŸãã
mprof plot
ããã«ãããmatplotlib ãå©çšããã¡ã¢ãªäœ¿çšéã®æšç§»ã°ã©ãã衚瀺ãããŸãïŒmatplotlibãã€ã³ã¹ããŒã«ãããŠããå ŽåïŒãç¹å®ã® .dat
ãã¡ã€ã«ãæå®ããŠããããããããšãå¯èœã§ãã
mprof plot mprofile_20250405123456.dat -o memory_usage_graph.png
-o
ãªãã·ã§ã³ã§ã°ã©ããç»åãã¡ã€ã«ãšããŠä¿åã§ããŸãã
mprof
ã³ãã³ãã«ã¯ä»ã«ããµãã³ãã³ãããããŸã:
mprof list
: èšé²ããã.dat
ãã¡ã€ã«ã®äžèŠ§ã衚瀺ããŸããmprof clean
: èšé²ããããã¹ãŠã®.dat
ãã¡ã€ã«ãåé€ããŸããmprof rm <file>
: ç¹å®ã®.dat
ãã¡ã€ã«ãåé€ããŸãã
2. Jupyter / IPython ã§ã®äœ¿çš (%memit, %%memit) âš
Jupyter Notebook ã IPython ç°å¢ã§ã¯ãããã«æ軜ã«ã¡ã¢ãªãããã¡ã€ãªã³ã°ãè¡ããããžãã¯ã³ãã³ããæäŸãããŠããŸãã
ãŸããæ¡åŒµæ©èœãããŒãããŸãã
%load_ext memory_profiler
%memit
(ã©ã€ã³ããžãã¯): ç¹å®ã® Python æã®å®è¡ã«äŒŽãã¡ã¢ãªäœ¿çšéã®å€åã枬å®ããŸãã
import numpy as np
# %memit ã䜿ã£ãŠ numpy é
åçæã®ã¡ã¢ãªå¢å éãèšæž¬
%memit large_array = np.zeros((1000, 1000))
åºåäŸ:
peak memory: 150.24 MiB, increment: 7.63 MiB
peak memory
ã¯ãã®è¡ãå®è¡ããåŸã®ããŒã¯ã¡ã¢ãªäœ¿çšéãincrement
ã¯ãã®è¡ã®å®è¡ã«ããã¡ã¢ãªå¢å éã瀺ããŸãã
%%memit
(ã»ã«ããžãã¯): ã»ã«å
šäœã®ã³ãŒãå®è¡ã«äŒŽãã¡ã¢ãªäœ¿çšéã®å€åã枬å®ããŸãã
%%memit
def process_data(size):
data = list(range(size))
processed = [x * 2 for x in data]
return processed
result = process_data(10**6)
åºåäŸ:
peak memory: 185.50 MiB, increment: 43.18 MiB
ãããã®ããžãã¯ã³ãã³ãã䜿ããšãã³ãŒããçŽæ¥å€æŽããããšãªããã€ã³ã¿ã©ã¯ãã£ãã«ã¡ã¢ãªäœ¿çšéããã§ãã¯ã§ãããããããŒã¿åæãå®éšçãªã³ãŒãèšè¿°ã®éã«éåžžã«äŸ¿å©ã§ãããã ããJupyter Notebook ã®ãã£ãã·ã¥ã®æåã«ãããdel
ã§å€æ°ãåé€ããŠãæåŸ
éãã«ã¡ã¢ãªã解æŸãããªãããã«èŠããå Žåãããç¹ã«ã¯æ³šæãå¿
èŠã§ãã
3. ç¹å®é¢æ°ã®ãããã¡ã€ãªã³ã° (ãã³ã¬ãŒã¿ãªã)
ãœãŒã¹ã³ãŒããå€æŽããã«ç¹å®ã®é¢æ°ã ãããããã¡ã€ãªã³ã°ãããå ŽåããããŸããmemory_profiler
ã¢ãžã¥ãŒã«ã¯ããã°ã©ã çã«äœ¿çšããããšãå¯èœã§ãã
from memory_profiler import memory_usage
def function_to_profile():
a = [1] * (10**6)
b = [2] * (5 * 10**6)
del b
return a
def another_function():
c = "some string" * 1000
return c
if __name__ == '__main__':
# function_to_profile ã®å®è¡äžã®ã¡ã¢ãªäœ¿çšéã 0.1 ç§ééã§ååŸ
# timeout ã¯èšæž¬æéã®äžéïŒç§ïŒãNone ã§å¶éãªã
# retval=True ã§é¢æ°ã®æ»ãå€ãååŸ
mem_usage, return_value = memory_usage(
(function_to_profile, (), {}), # (é¢æ°, argsã¿ãã«, kwargsèŸæž)
interval=0.1,
timeout=None,
retval=True,
max_usage=True # æ»ãå€ãšããŠæ倧ã¡ã¢ãªäœ¿çšéãè¿ã
)
print(f"function_to_profile ã®æ倧ã¡ã¢ãªäœ¿çšé: {max(mem_usage) if mem_usage else 'N/A'} MiB")
print(f"æ»ãå€ã®æåã®10èŠçŽ : {return_value[:10]}")
# å¥ã®é¢æ°ã®å®è¡ (ããã¯ãããã¡ã€ãªã³ã°ãããªã)
other_result = another_function()
print("another_function å®è¡å®äº")
memory_usage
é¢æ°ã䜿ãããšã§ãæå®ããé¢æ° (ãããã»ã¹) ã®å®è¡äžã®ã¡ã¢ãªäœ¿çšéããªã¹ããšããŠååŸã§ããŸããinterval
ã§ãµã³ããªã³ã°ééããtimeout
ã§èšæž¬æéãå¶åŸ¡ã§ããŸããmax_usage=True
ãæå®ãããšãèšé²ãããã¡ã¢ãªäœ¿çšéã®ãªã¹ãã®ä»£ããã«ãåäžã®æ倧ã¡ã¢ãªäœ¿çšéã®å€ãè¿ããŸãã
å®è·µçãªãŠãŒã¹ã±ãŒã¹ãšãã³ãð¡
memory_profiler
ã¯ä»¥äžã®ãããªå Žé¢ã§ç¹ã«åœ¹ç«ã¡ãŸãã
- ã¡ã¢ãªãªãŒã¯ã®ç¹å®: é·æéå®è¡ããã¢ããªã±ãŒã·ã§ã³ã§
mprof
ã䜿ããã¡ã¢ãªäœ¿çšéãæéãšãšãã«å¢å ãç¶ããç®æãæ¢ããŸãã - ããŒã¿åŠçãã€ãã©ã€ã³ã®æé©å: 倧èŠæš¡ãªããŒã¿ã»ãããæ±ãéãååŠçã¹ãããã§ã®ã¡ã¢ãªæ¶è²»ã
@profile
ã%%memit
ã§ç¢ºèªããããã«ããã¯ãšãªã£ãŠããç®æïŒäŸãã°ã巚倧ãªäžéããŒã¿ãã¡ã¢ãªäžã«ä¿æããŠããç®æïŒãç¹å®ããŠæ¹åããŸãïŒäŸïŒãžã§ãã¬ãŒã¿ã®äœ¿çšããã£ã³ã¯åŠçã®å°å ¥ïŒã - ã¢ã«ãŽãªãºã æ¯èŒ: åãç®çãéæããè€æ°ã®ã¢ã«ãŽãªãºã ã«ã€ããŠãå®è¡æéã ãã§ãªãã¡ã¢ãªå¹çãæ¯èŒæ€èšããŸãã
- ã©ã€ãã©ãª/é¢æ°ã®ã¡ã¢ãªç¹æ§ç解: 䜿çšããŠããã©ã€ãã©ãªã®ç¹å®ã®é¢æ°ãå éšã§ã©ãã ãã®ã¡ã¢ãªãæ¶è²»ãããã確èªããŸãã
å¹æçã«äœ¿ãããã®ãã³ã
- 代衚çãªã¯ãŒã¯ããŒãã§èšæž¬ãã: å®éã®å©çšç¶æ³ã«è¿ãããŒã¿ãåŠçãããŒã§ãããã¡ã€ãªã³ã°ãè¡ãããšãéèŠã§ãã
- ãããã¡ã€ãªã³ã°ã®ãªãŒããŒããããèæ
®ãã:
memory_profiler
èªäœãå€å°ã®ã¡ã¢ãªãšCPUæéãæ¶è²»ããŸããç¹ã«interval
ãçãèšå®ãããšãªãŒããŒããããå¢å ããå¯èœæ§ããããŸãã - ä»ã®ããŒã«ãšçµã¿åããã: CPUæéã®ããã«ããã¯ãç¹å®ãã
cProfile
ãline_profiler
ãšçµã¿åãããããšã§ãããã©ãŒãã³ã¹å šäœã俯ç°çã«åæã§ããŸãããŸãcProfile
ã§é ãé¢æ°ãç¹å®ãã次ã«ãã®é¢æ°ã«å¯ŸããŠmemory_profiler
ãline_profiler
ãé©çšãããšãã£ã䜿ãæ¹ãå¹æçã§ãã - çµæã解éãã: ã¡ã¢ãªäœ¿çšéã®å¢å ãå¿ ãããåé¡ãšã¯éããŸãããå¿ èŠãªããŒã¿ãä¿æããããã®ã¡ã¢ãªç¢ºä¿ã¯åœç¶çºçããŸããåé¡ãšãªãã®ã¯ãäžèŠã«ãªã£ãã¡ã¢ãªã解æŸãããªããªãŒã¯ããéå¹çãªããŒã¿æ§é ã«ããéå°ãªã¡ã¢ãªæ¶è²»ã§ãã
ãŸãšã
memory_profiler
ã¯ãPython ã¢ããªã±ãŒã·ã§ã³ã®ã¡ã¢ãªäœ¿çšéãç解ããæé©åããããã®åŒ·åãªããŒã«ã§ããè¡ããšã®è©³çŽ°ãªåæããæç³»åã§ã®ç£èŠãŸã§ãæ§ã
ãªè§åºŠããã¡ã¢ãªã®æåãæ¢ãããšãã§ããŸãã
ã€ã³ã¹ããŒã«ã䜿ãæ¹ãæ¯èŒçç°¡åãªã®ã§ãã¡ã¢ãªé¢é£ã®åé¡ã«çŽé¢ãããšãããããå¹ççãªã³ãŒããç®æãéã«ã¯ããã²ãã®ã©ã€ãã©ãªã掻çšããŠã¿ãŠãã ãããã¡ã¢ãªäœ¿çšéãæèããéçºã¯ãã¢ããªã±ãŒã·ã§ã³ã®å®å®æ§ãšããã©ãŒãã³ã¹åäžã«ç¹ãããŸãïŒ ðªð
å ¬åŒããã¥ã¡ã³ãããªãœãŒã¹ã¯ PyPI ã® memory-profiler ããŒãž ãåç §ããŠãã ããã
ã³ã¡ã³ã