- 内容提要
- 前言
- 作者简介
- 封面简介
- 第1章 理解高性能 Python
- 第2章 通过性能分析找到瓶颈
- 2.1 高效地分析性能
- 2.2 Julia 集合的介绍
- 2.3 计算完整的 Julia 集合
- 2.4 计时的简单方法——打印和修饰
- 2.5 用 UNIX 的 time 命令进行简单的计时
- 2.6 使用 cProfile 模块
- 2.7 用 runsnakerun 对 cProfile 的输出进行可视化
- 2.8 用 line_profiler 进行逐行分析
- 2.9 用 memory_profiler 诊断内存的用量
- 2.10 用 heapy 调查堆上的对象
- 2.11 用 dowser 实时画出变量的实例
- 2.12 用 dis 模块检查 CPython 字节码
- 2.13 在优化期间进行单元测试保持代码的正确性
- 2.14 确保性能分析成功的策略
- 2.15 小结
- 第3章 列表和元组
- 第4章 字典和集合
- 第5章 迭代器和生成器
- 第6章 矩阵和矢量计算
- 第7章 编译成 C
- 第8章 并发
- 第9章 multiprocessing 模块
- 第10章 集群和工作队列
- 第11章 使用更少的 RAM
- 第12章 现场教训
2.10 用 heapy 调查堆上的对象
Guppy项目有一个内存堆的调查工具叫作heapy,可以让你查看Python堆中对象的数量以及每个对象的大小。当你需要知道某一时刻有多少对象被使用以及它们是否被垃圾收集时,你尤其需要这种深入解释器内部去了解内存中实际内容的能力。如果你受困于内存泄漏(可能由于你的对象的引用隐藏于一个复杂系统中),那么这个工具能帮你找到问题的关键点。
当你在审查你的代码,看它是否如你预期那样生成对象时,你会发现这个工具非常有用——结果很可能令你吃惊,并为你带来新的优化方向。
为了使用heapy,你需要用命令pip install guppy安装guppy包。
例2-12的代码是Julia代码的一个略有修改的版本。calc_pure_python使用了堆对象hpy,我们在三个地方打印堆的内容。
例2-12 用heapy查看代码运行时对象数量的变化
def calc_pure_python(draw_output, desired_width, max_iterations): ... while xcoord < x2: x.append(xcoord) xcoord += x_step from guppy import hpy; hp = hpy() print "heapy after creating y and x lists of floats" h = hp.heap() print h print zs = [] cs = [] for ycoord in y: for xcoord in x: zs.append(complex(xcoord, ycoord)) cs.append(complex(c_real, c_imag)) print "heapy after creating zs and cs using complex numbers" h = hp.heap() print h print print "Length of x:", len(x) print "Total elements:", len(zs) start_time = time.time() output = calculate_z_serial_purepython(max_iterations, zs, cs) end_time = time.time() secs = end_time - start_time print calculate_z_serial_purepython.func_name + " took", secs, "seconds" print print "heapy after calling calculate_z_serial_purepython" h = hp.heap() print h print
例2-13的输出显示了内存的使用在创建zs和cs列表后变得有趣:它增长了大约80MB,因为2000000个复数对象消耗了64000000字节。这些复数对象占据了目前使用的大多数内存。如果你想要优化这个程序的内存用量,这个结果可用于揭示目前保存的对象数量以及它们总共占用的空间。
例2-13 heapy输出显示了我们代码执行时每一个主要阶段的对象总数
$ python julia1_guppy.py heapy after creating y and x lists of floats Partition of a set of 27293 objects. Total size = 3416032 bytes. Index Count % Size % Cumulative % Kind (class / dict of class) 0 10960 40 1050376 31 1050376 31 str 1 5768 21 465016 14 1515392 44 tuple 2 199 1 210856 6 1726248 51 dict of type 3 72 0 206784 6 1933032 57 dict of module 4 1592 6 203776 6 2136808 63 types.CodeType 5 313 1 201304 6 2338112 68 dict (no owner) 6 1557 6 186840 5 2524952 74 function 7 199 1 177008 5 2701960 79 type 8 124 0 135328 4 2837288 83 dict of class 9 1045 4 83600 2 2920888 86 __builtin__.wrapper_descriptor <91 more rows. Type e.g. '_.more' to view.> heapy after creating zs and cs using complex numbers Partition of a set of 2027301 objects. Total size = 83671256 bytes. Index Count % Size % Cumulative % Kind (class / dict of class) 0 2000000 99 6400000 76 64000000 76 complex 1 185 0 16295368 19 80295368 96 list 2 10962 1 1050504 1 81345872 97 str 3 5767 0 464952 1 81810824 98 tuple 4 199 0 210856 0 82021680 98 dict of type 5 72 0 206784 0 82228464 98 dict of module 6 1592 0 203776 0 82432240 99 types.CodeType 7 319 0 202984 0 82635224 99 dict (no owner) 8 1556 0 186720 0 82821944 99 function 9 199 0 177008 0 82998952 99 type <92 more rows. Type e.g. '_.more' to view.> Length of x: 1000 Total elements: 1000000 calculate_z_serial_purepython took 13.2436609268 seconds heapy after calling calculate_z_serial_purepython Partition of a set of 2127696 objects. Total size = 94207376 bytes. Index Count % Size % Cumulative % Kind (class / dict of class) 0 2000000 94 64000000 68 64000000 68 complex 1 186 0 24421904 26 88421904 94 list 2 100965 5 2423160 3 90845064 96 int 3 10962 1 1050504 1 91895568 98 str 4 5767 0 464952 0 92360520 98 tuple 5 199 0 210856 0 92571376 98 dict of type 6 72 0 206784 0 92778160 98 dict of module 7 1592 0 203776 0 92981936 99 types.CodeType 8 319 0 202984 0 93184920 99 dict (no owner) 9 1556 0 186720 0 93371640 99 function <92 more rows. Type e.g. '_.more' to view.>
第三段显示了在计算完Julia集合后,我们占用了94MB的内存。除了之前的复数,我们现在还保存了大量的整数,列表中的项目也变多了。
hpy``.setrelheap()可以用来创建一个内存断点,当后续调用hpy``.heap()时就会产生一个跟这个断点的差额。这样你就可以略过断点前由Python内部操作导致的内存分配。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论