python 内存监控模块之memory_profiler

简介:

0. memory_profiler是干嘛的

This is a python module for monitoring memory consumption of a process as well as line-by-line analysis of memory consumption for python programs. It is a pure python module and has the psutil module as optional (but highly recommended) dependencies.

memory_profiler是监控python进程的神器,它可以分析出每一行代码所增减的内存状况。

1. 入门例子

#del3.py

复制代码
import time
@profile
def my_func():
    a = [1] * (10 ** 6)
    b = [2] * (2 * 10 ** 7)
    time.sleep(10)
    del b
    del a
    print "+++++++++"

if __name__ == '__main__':
    my_func()
复制代码

结果

复制代码
$python -m memory_profiler del3.py
+++++++++
Filename: del3.py

Line #    Mem usage    Increment   Line Contents
================================================
     2   10.293 MiB    0.000 MiB   @profile
     3                             def my_func():
     4   17.934 MiB    7.641 MiB       a = [1] * (10 ** 6)
     5  170.523 MiB  152.590 MiB       b = [2] * (2 * 10 ** 7)
     6  170.527 MiB    0.004 MiB       time.sleep(10)
     7   17.938 MiB -152.590 MiB       del b
     8   10.305 MiB   -7.633 MiB       del a
     9   10.309 MiB    0.004 MiB       print "+++++++++"
复制代码

代码执行一遍,然后给出具体代码在某一步占用的内存,通过内存加减可以看出某个对象的大小。

2. 对象不删除,直接赋值内存是否会继续增长

#对比1

复制代码
@profile
def my_func():
    a = 'a' * 1024 * 1024 * 1024;
    a = 'a' * 1024 * 1024
    a = 'a' * 1024
    del a
    print "+++++++++"

if __name__ == '__main__':
    my_func()
复制代码

结果

复制代码
Line #    Mem usage    Increment   Line Contents
================================================
     1   10.293 MiB    0.000 MiB   @profile
     2                             def my_func():
     3 1034.301 MiB 1024.008 MiB       a = 'a' * 1024 * 1024 * 1024;
     4   11.285 MiB -1023.016 MiB       a = 'a' * 1024 * 1024
     5   11.285 MiB    0.000 MiB       a = 'a' * 1024
     6   11.285 MiB    0.000 MiB       del a
     7   11.289 MiB    0.004 MiB       print "+++++++++"
复制代码

#对比2

复制代码
@profile
def my_func():
    a = 'a' * 1024 * 1024 * 1024;
    del a
    a = 'a' * 1024 * 1024
    del a
    a = 'a' * 1024
    del a
    print "+++++++++"

if __name__ == '__main__':
    my_func()
复制代码

结果

复制代码
Line #    Mem usage    Increment   Line Contents
================================================
     1   10.293 MiB    0.000 MiB   @profile
     2                             def my_func():
     3 1034.301 MiB 1024.008 MiB       a = 'a' * 1024 * 1024 * 1024;
     4   10.297 MiB -1024.004 MiB       del a
     5   11.285 MiB    0.988 MiB       a = 'a' * 1024 * 1024
     6   11.285 MiB    0.000 MiB       del a
     7   11.285 MiB    0.000 MiB       a = 'a' * 1024
     8   11.285 MiB    0.000 MiB       del a
     9   11.289 MiB    0.004 MiB       print "+++++++++"
复制代码

结论:是否 del对象没有影响,新赋的值会替代旧的值

3. 对象赋值是否会增加同样的内存

#对比1

复制代码
@profile
def my_func():
    a = 'a' * 1024 * 1024 * 1024;
    b = a
    del a
    print "+++++++++"

if __name__ == '__main__':
    my_func()
复制代码

结果

复制代码
Line #    Mem usage    Increment   Line Contents
================================================
     1   10.293 MiB    0.000 MiB   @profile
     2                             def my_func():
     3 1034.301 MiB 1024.008 MiB       a = 'a' * 1024 * 1024 * 1024;
     4 1034.301 MiB    0.000 MiB       b = a
     5 1034.301 MiB    0.000 MiB       del a
     6 1034.305 MiB    0.004 MiB       print "+++++++++"
复制代码

#对比2

复制代码
@profile
def my_func():
    a = 'a' * 1024 * 1024 * 1024;
    b = a
    del a
    del b
    print "+++++++++"

if __name__ == '__main__':
    my_func()
复制代码

结果

复制代码
Line #    Mem usage    Increment   Line Contents
================================================
     1   10.297 MiB    0.000 MiB   @profile
     2                             def my_func():
     3 1034.305 MiB 1024.008 MiB       a = 'a' * 1024 * 1024 * 1024;
     4 1034.305 MiB    0.000 MiB       b = a
     5 1034.305 MiB    0.000 MiB       del a
     6   10.301 MiB -1024.004 MiB       del b
     7   10.305 MiB    0.004 MiB       print "+++++++++"
复制代码

结论,把a赋值给b,内存没有增加。但是只删除其中一个对象的时候,内存不会减。

4. 另一种等价的启动方式

复制代码
from memory_profiler import profile
@profile(precision=4)
def my_func():
    a = 'a' * 1024 * 1024 * 1024;
    del a
    a = 'a' * 1024 * 1024
    del a
    a = 'a' * 1024
    del a
    print "+++++++++"

if __name__ == '__main__':
    my_func()
复制代码

结果

复制代码
$python -m memory_profiler del3.py
+++++++++
Filename: del3.py

Line #    Mem usage    Increment   Line Contents
================================================
     2  10.3867 MiB   0.0000 MiB   @profile(precision=4)
     3                             def my_func():
     4 1034.3945 MiB 1024.0078 MiB       a = 'a' * 1024 * 1024 * 1024;
     5  10.3906 MiB -1024.0039 MiB       del a
     6  11.3789 MiB   0.9883 MiB       a = 'a' * 1024 * 1024
     7  11.3789 MiB   0.0000 MiB       del a
     8  11.3789 MiB   0.0000 MiB       a = 'a' * 1024
     9  11.3789 MiB   0.0000 MiB       del a
    10  11.3828 MiB   0.0039 MiB       print "+++++++++"
复制代码

5. 非python内置对象例子

复制代码
from memory_profiler import profile
import networkx as nx

@profile(precision=4)
def my_func():
    a = 'a' * 1024 * 1024 * 1024;
    del a
    G = nx.Graph()
    G.add_node(1)
    G.add_nodes_from([i for i in range(10000)])
    G.add_nodes_from([i for i in range(10000, 20000)])
    G.add_edges_from([(1,2), (1,4), (2, 9), (4, 1), (3, 8)])
    del G
    print "++++++"

if __name__ == '__main__':
    my_func()
复制代码

结果

复制代码
$python del3.py
++++++
Filename: del3.py

Line #    Mem usage    Increment   Line Contents
================================================
     4  23.4844 MiB   0.0000 MiB   @profile(precision=4)
     5                             def my_func():
     6 1047.4922 MiB 1024.0078 MiB       a = 'a' * 1024 * 1024 * 1024;
     7  23.4883 MiB -1024.0039 MiB       del a 
     8  23.4883 MiB   0.0000 MiB       G = nx.Graph()
     9  23.4883 MiB   0.0000 MiB       G.add_node(1)
    10  31.3359 MiB   7.8477 MiB       G.add_nodes_from([i for i in range(10000)]) 
    11  36.9219 MiB   5.5859 MiB       G.add_nodes_from([i for i in range(10000, 20000)]) 
    12  36.9219 MiB   0.0000 MiB       G.add_edges_from([(1,2), (1,4), (2, 9), (4, 1), (3, 8)])
    13  25.9219 MiB -11.0000 MiB       del G
    14  25.9258 MiB   0.0039 MiB       print "++++++"
复制代码

6. 类怎么使用呢

#del4.py

复制代码
from memory_profiler import profile

class people:
    name = ''
    age = 0
    __weight = 0

    def __init__(self,n,a,w):
        self.name = n
        self.age = a
        self.__weight = w

    @profile(precision=4)
    def speak(self):
        a = 'a' * 1024
        b = 'b' * 1024 * 1024
        print("%s is speaking: I am %d years old" % (self.name,self.age))



if __name__ == '__main__':
    p = people('tom', 10, 30)
    p.speak()
复制代码

结果

复制代码
$python del4.py
tom is speaking: I am 10 years old
Filename: del4.py

Line #    Mem usage    Increment   Line Contents
================================================
    13   9.4219 MiB   0.0000 MiB       @profile(precision=4)
    14                                 def speak(self):  
    15   9.4258 MiB   0.0039 MiB           a = 'a' * 1024
    16  10.4297 MiB   1.0039 MiB           b = 'b' * 1024 * 1024
    17  10.4336 MiB   0.0039 MiB           print("%s is speaking: I am %d years old" % (self.name,self.age)) 
复制代码

7. 随时间内存统计

#test.py

复制代码
import time

@profile
def test1():
    n = 10000
    a = [1] * n
    time.sleep(1)
    return a

@profile
def test2():
    n = 100000
    b = [1] * n
    time.sleep(1)
    return b

if __name__ == "__main__":
    test1()
    test2()
复制代码

test.py 里有两个两个待分析的函数(@profile标识),为了形象地看出内存随时间的变化,每个函数内sleep 1s,执行

mprof run test.py

如果执行成功,结果这样

$ mprof run test.py
mprof: Sampling memory every 0.1s
running as a Python program...

结果会生成一个.dat文件,如"mprofile_20160716170529.dat",里面记录了内存随时间的变化,可用下面的命令以图片的形式展示出来:

mprof plot

8. API

memory_profiler提供很多包给第三方代码,如

>>> from memory_profiler import memory_usage
>>> mem_usage = memory_usage(-1, interval=.2, timeout=1)
>>> print(mem_usage)
    [7.296875, 7.296875, 7.296875, 7.296875, 7.296875]

memory_usage(proc=-1, interval=.2, timeout=None)返回一段时间的内存值,其中proc=-1表示此进程,这里可以指定特定的进程号;interval=.2表示监控的时间间隔是0.2秒;timeout=1表示总共的时间段为1秒。那结果就返回5个值。

如果要返回一个函数的内存消耗,示例

复制代码
def f(a, n=100):
     import time
     time.sleep(2)
     b = [a] * n
     time.sleep(1)
     return b

from memory_profiler import memory_usage
print memory_usage((f, (2,), {'n' : int(1e6)}))
复制代码

这里执行了 f(1, n=int(1e6)) ,并返回在执行此函数时的内存消耗。

9. 优化实例

对比str & int

复制代码
from datetime import datetime
@profile
def my_func():
    beg = datetime.now()
    a = {}
    for i in range(1000000):
        a[i] = i
        #a[str(i)] = i
    print "+++++++++"
    del a
    print "+++++++++"
    end = datetime.now()
    print "time:", end - beg

if __name__ == '__main__':
    my_func()
复制代码

用a[i] = i,结果

复制代码
+++++++++
+++++++++
time: 0:06:14.790899
Filename: int.py

Line #    Mem usage    Increment   Line Contents
================================================
     2   14.727 MiB    0.000 MiB   @profile
     3                             def my_func():
     4   14.734 MiB    0.008 MiB       beg = datetime.now()
     5   14.734 MiB    0.000 MiB       a = {}
     6   94.031 MiB   79.297 MiB       for i in range(1000000):
     7   94.031 MiB    0.000 MiB           a[i] = i
     8                                     #a[str(i)] = i
     9   86.402 MiB   -7.629 MiB       print "+++++++++"
    10   38.398 MiB  -48.004 MiB       del a
    11   38.398 MiB    0.000 MiB       print "+++++++++"
    12   38.398 MiB    0.000 MiB       end = datetime.now()
    13   38.406 MiB    0.008 MiB       print "time:", end - beg
复制代码

用a[str(i)] = i,结果

复制代码
+++++++++
+++++++++
time: 0:06:00.288052
Filename: int.py

Line #    Mem usage    Increment   Line Contents
================================================
     2   14.723 MiB    0.000 MiB   @profile
     3                             def my_func():
     4   14.730 MiB    0.008 MiB       beg = datetime.now()
     5   14.730 MiB    0.000 MiB       a = {}
     6  140.500 MiB  125.770 MiB       for i in range(1000000):
     7                                     #a[i] = i
     8  140.500 MiB    0.000 MiB           a[str(i)] = i
     9  132.871 MiB   -7.629 MiB       print "+++++++++"
    10   38.539 MiB  -94.332 MiB       del a
    11   38.539 MiB    0.000 MiB       print "+++++++++"
    12   38.539 MiB    0.000 MiB       end = datetime.now()
    13   38.547 MiB    0.008 MiB       print "time:", end - beg
复制代码

 







本文转自jihite博客园博客,原文链接:http://www.cnblogs.com/kaituorensheng/p/5669861.html,如需转载请自行联系原作者


相关文章
|
2月前
|
监控 算法 安全
深度洞察内网监控电脑:基于Python的流量分析算法
在当今数字化环境中,内网监控电脑作为“守城卫士”,通过流量分析算法确保内网安全、稳定运行。基于Python的流量分析算法,利用`scapy`等工具捕获和解析数据包,提取关键信息,区分正常与异常流量。结合机器学习和可视化技术,进一步提升内网监控的精准性和效率,助力企业防范潜在威胁,保障业务顺畅。本文深入探讨了Python在内网监控中的应用,展示了其实战代码及未来发展方向。
|
6天前
|
监控 算法 安全
基于 Python 广度优先搜索算法的监控局域网电脑研究
随着局域网规模扩大,企业对高效监控计算机的需求增加。广度优先搜索(BFS)算法凭借其层次化遍历特性,在Python中可用于实现局域网内的计算机设备信息收集、网络连接状态监测及安全漏洞扫描,确保网络安全与稳定运行。通过合理选择数据结构与算法,BFS显著提升了监控效能,助力企业实现智能化的网络管理。
22 6
|
10天前
|
人工智能 自然语言处理 Shell
[oeasy]python070_如何导入模块_导入模块的作用_hello_dunder_双下划线
本文介绍了如何在Python中导入模块及其作用,重点讲解了`__hello__`模块的导入与使用。通过`import`命令可以将外部模块引入当前环境,增强代码功能。例如,导入`__hello__`模块后可输出“Hello world!”。此外,还演示了如何使用`help()`和`dir()`函数查询模块信息,并展示了导入多个模块的方法。最后,通过一个实例,介绍了如何利用`jieba`、`WordCloud`和`matplotlib`模块生成词云图。总结来说,模块是封装好的功能部件,能够简化编程任务并提高效率。未来将探讨如何创建自定义模块。
31 8
|
8天前
|
缓存 Shell 开发工具
[oeasy]python071_我可以自己做一个模块吗_自定义模块_引入模块_import_diy
本文介绍了 Python 中模块的导入与自定义模块的创建。首先,我们回忆了模块的概念,即封装好功能的部件,并通过导入 `__hello__` 模块实现了输出 "hello world!" 的功能。接着,尝试创建并编辑自己的模块 `my_file.py`,引入 `time` 模块以获取当前时间,并在其中添加自定义输出。
21 4
|
3月前
|
Python
Python Internet 模块
Python Internet 模块。
139 74
|
22天前
|
监控 Java 计算机视觉
Python图像处理中的内存泄漏问题:原因、检测与解决方案
在Python图像处理中,内存泄漏是常见问题,尤其在处理大图像时。本文探讨了内存泄漏的原因(如大图像数据、循环引用、外部库使用等),并介绍了检测工具(如memory_profiler、objgraph、tracemalloc)和解决方法(如显式释放资源、避免循环引用、选择良好内存管理的库)。通过具体代码示例,帮助开发者有效应对内存泄漏挑战。
36 1
|
4月前
|
算法 数据安全/隐私保护 开发者
马特赛特旋转算法:Python的随机模块背后的力量
马特赛特旋转算法是Python `random`模块的核心,由松本真和西村拓士于1997年提出。它基于线性反馈移位寄存器,具有超长周期和高维均匀性,适用于模拟、密码学等领域。Python中通过设置种子值初始化状态数组,经状态更新和输出提取生成随机数,代码简单高效。
151 63
|
4月前
|
持续交付 Python
如何在Python中自动解决模块和包的依赖冲突?
完全自动解决所有依赖冲突可能并不总是可行,特别是在复杂的项目中。有时候仍然需要人工干预和判断。自动解决的方法主要是提供辅助和便捷,但不能完全替代人工的分析和决策😉。
|
3月前
|
存储 运维 监控
探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
86 20
|
2月前
|
Python
[oeasy]python057_如何删除print函数_dunder_builtins_系统内建模块
本文介绍了如何删除Python中的`print`函数,并探讨了系统内建模块`__builtins__`的作用。主要内容包括: 1. **回忆上次内容**:上次提到使用下划线避免命名冲突。 2. **双下划线变量**:解释了双下划线(如`__name__`、`__doc__`、`__builtins__`)是系统定义的标识符,具有特殊含义。
40 3

热门文章

最新文章