- 内容提要
- 前言
- 作者简介
- 封面简介
- 第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章 现场教训
11.2 理解集合中的 RAM 使用
你可能想知道你是否能够请求Python关于每个对象所使用的RAM大小。Python的sys.getsizeof(obj)调用会告诉我们一些关于对象所使用的内存情况(绝大多数而不是全部对象提供了这个调用)。如果你以前没有见过,那么提醒一下它不会给你所期待的关于容器的答案!
让我们通过查看一些基础类型来开始。在Python中的int是一个可变尺寸的对象,它起始于一个常规的整数,如果你计数超过sys.maxint(在Ian的64位笔记本电脑上,这个值是9223372036854775807),它就会转变为一个长整数。
作为一个常规的整数,它占用24字节(对象有许多开销);而作为长整数,它消耗36字节:
In [1]: sys.getsizeof(int()) Out[1]: 24 In [2]: sys.getsizeof(1) Out[2]: 24 In [3]: n=sys.maxint+1 In [4]: sys.getsizeof(n) Out[4]: 36
我们可以对byte string做同样的检查。一个空字符串消耗37字节,每一个多加的字符增加了1字节的开销:
In [21]: sys.getsizeof(b"") Out[21]: 37 In [22]: sys.getsizeof(b"a") Out[22]: 38 In [23]: sys.getsizeof(b"ab") Out[23]: 39 In [26]: sys.getsizeof(b"cde") Out[26]: 40
当我们使用一个列表时,我们看见了不同的表现。getsizeof没有对列表的内容计数,仅仅是列表自身的开销。一个空列表消耗72字节,在一台64位笔记本电脑上,列表中的每一项占用了8个额外字节:
# goes up in 8-byte steps rather than the 24 we might expect! In [36]: sys.getsizeof([]) Out[36]: 72 In [37]: sys.getsizeof([1]) Out[37]: 80 In [38]: sys.getsizeof([1,2]) Out[38]: 88
如果我们使用byte string,这就更明显了——我们期望你看到比getsizeof所报告的要大得多的开销。
In [40]: sys.getsizeof([b""]) Out[40]: 80 In [41]: sys.getsizeof([b"abcdefghijklm"]) Out[41]: 80 In [42]: sys.getsizeof([b"a", b"b"]) Out[42]: 88
getsizeof只报告了一部分开销,常常仅仅是父对象的开销。就如之前所提示的那样,它也不总是被实现了的,所以可以作有限的用途。
一个轻量级的更好的工具是asizeof,它会遍历容器的层级结构并对它所发现的每个对象做出最好的猜测,给整体大小增加了尺寸。注意它的速度相当慢。
除了依赖于猜测和假设之外,它也不能计算幕后的内存分配(例如,一个包装了C库的模块可能没有报告在C库中所分配的字节数)。最好把它用来作为一个指导。我们倾向于使用memit,因为它给了我们在问题机器上的准确的内存使用计数。
你如下所示使用asizeof:
In [1]: %run asizeof.py In [2]: asizeof([b"abcdefghijklm"]) Out[2]: 136
我们可以检查它对一个大列表所做的估算——这里我们将使用100000000个整数:
# this takes 30 seconds to run! In [1]: asizeof([x for x in xrange(10000000)]) # 1e7 integers Out[1]: 321528064
我们可以通过使用memit来查看进程如何增长来验证这个估算。在这种情况下,数字是非常接近的:
In [2]: %memit([x for x in xrange(10000000)]) peak memory: 330.64 MiB, increment: 310.62 MiB
asizeof一般要比使用memit来得更慢,但是当你分析小对象时,asizeof是可以用上的。memit可能对真实世界的应用来说更加有用,因为进程的实际内存使用是测量出来的,而不是推导出来的。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论