itf*_*itf 9 python memory-leaks memory-profiling python-3.x
我正在与Pympler进行一些完整性检查,以确保在我尝试分析实际脚本时我理解结果,但我对结果感到有些困惑.以下是我尝试的健全性检查:
SANITY CHECK 1:我启动Python(3)控制台并执行以下操作:
from pympler import summary, muppy
sum = summary.summarize(muppy.get_objects())
summary.print_(sum)
Run Code Online (Sandbox Code Playgroud)
这导致以下总结:
types | # objects | total size
==================================== | =========== | ============
<class 'str | 16047 | 1.71 MB
<class 'dict | 2074 | 1.59 MB
<class 'type | 678 | 678.27 KB
<class 'code | 4789 | 673.68 KB
<class 'set | 464 | 211.00 KB
<class 'list | 1319 | 147.16 KB
<class 'tuple | 1810 | 120.03 KB
<class 'weakref | 1269 | 99.14 KB
<class 'wrapper_descriptor | 1124 | 87.81 KB
<class 'builtin_function_or_method | 918 | 64.55 KB
<class 'abc.ABCMeta | 64 | 62.25 KB
<class 'method_descriptor | 877 | 61.66 KB
<class 'int | 1958 | 58.88 KB
<class 'getset_descriptor | 696 | 48.94 KB
function (__init__) | 306 | 40.64 KB
Run Code Online (Sandbox Code Playgroud)
如果我刚刚启动了一个新的Python会话,那么内存中的所有字符串,字典,列表等都是如何?我不认为Pympler会在所有会话中总结结果(这没有任何意义,但这是我能想到的唯一可能性).
SANITY CHECK 2:由于我不太了解tabula rasa Python会话的摘要结果,所以在定义一些变量/数据结构之后,让我们看一下总结的差异.我启动另一个控制台并执行以下操作:
from pympler import summary, muppy
sum = summary.summarize(muppy.get_objects())
a = {}
b = {}
c = {}
d = {'a': [0, 0, 1, 2], 't': [3, 3, 3, 1]}
sum1 = summary.summarize(muppy.get_objects())
summary.print_(summary.get_diff(sum, sum1))
Run Code Online (Sandbox Code Playgroud)
这导致以下总结:
types | # objects | total size
============================== | =========== | ============
<class 'list | 3247 | 305.05 KB
<class 'str | 3234 | 226.04 KB
<class 'int | 552 | 15.09 KB
<class 'dict | 1 | 480 B
function (_keys) | 0 | 0 B
function (get_path) | 0 | 0 B
function (http_open) | 0 | 0 B
function (memoize) | 0 | 0 B
function (see) | 0 | 0 B
function (recvfrom) | 0 | 0 B
function (rfind) | 0 | 0 B
function (wm_focusmodel) | 0 | 0 B
function (_parse_makefile) | 0 | 0 B
function (_decode_pax_field) | 0 | 0 B
function (__gt__) | 0 | 0 B
Run Code Online (Sandbox Code Playgroud)
我以为我刚刚初始化了四个新的词典(虽然3个是空的),为什么Muppy只显示1个新词典对象的区别?此外,为什么有成千上万的新字符串和列表,更不用说整数?
SANITY CHECK 3:再次,我开始一个新的Python会话,但这一次想看看Pympler如何处理更复杂的数据类型,如字典列表.
from pympler import muppy, summary
sum = summary.summarize(muppy.get_objects())
a = [{}, {}, {}, {'a': [0, 0, 1, 2], 't': [3, 3, 3, 1]}, {'a': [1, 2, 3, 4]}]
sum1 = summary.summarize(muppy.get_objects())
summary.print_(summary.get_diff(sum, sum1))
Run Code Online (Sandbox Code Playgroud)
其结果如下:
types | # objects | total size
===================================================== | =========== | ============
<class 'list | 3233 | 303.88 KB
<class 'str | 3270 | 230.71 KB
<class 'int | 554 | 15.16 KB
<class 'dict | 10 | 5.53 KB
<class 'code | 16 | 2.25 KB
<class 'type | 2 | 1.98 KB
<class 'tuple | 6 | 512 B
<class 'getset_descriptor | 4 | 288 B
function (__init__) | 2 | 272 B
<class '_frozen_importlib_external.SourceFileLoader | 3 | 168 B
<class '_frozen_importlib.ModuleSpec | 3 | 168 B
<class 'weakref | 2 | 160 B
function (__call__) | 1 | 136 B
function (Find) | 1 | 136 B
function (<lambda>) | 1 | 136 B
Run Code Online (Sandbox Code Playgroud)
即使列表和词典嵌套有点令人费解,按照我的计算,我添加了5个新词典和4个新列表.
有人能解释一下Muppy如何计算物体?
get_objects在新的Python会话中summary.summarize(muppy.get_objects())返回在启动和from pympler import summary, muppy运行期间实例化的任何对象,这解释了大量的计数。
get_objects2 两次调用的区别请记住,sum生成的对象summary.summarize()是在第一个快照之后创建的,这解释了“数千个新字符串和列表”。您可以通过将测试重写为以下方式来解决此问题:
from pympler import summary, muppy\no1 = muppy.get_objects()\na = {}\nb = {}\nc = {}\nd = {\'a\': [0, 0, 1, 2], \'t\': [3, 3, 3, 1]}\no2 = muppy.get_objects()\nsummary.print_(summary.get_diff(summary.summarize(o1), summary.summarize(o2)))\nRun Code Online (Sandbox Code Playgroud)\no1这将减少和其他几个对象的大列表的无关差异:
>>> for o in diff[\'+\']:\n... print("%s - %s" % (type(o), o if len(o) < 10 else "long list"))\n...\n<class \'str\'> - o2\n<class \'list\'> - long list\n<class \'dict\'> - {\'a\': [0, 0, 1, 2], \'t\': [3, 3, 3, 1]}\n<class \'list\'> - [\'o2\', \'muppy\', \'get_objects\']\n<class \'list\'> - [0, 0, 1, 2]\n<class \'list\'> - [3, 3, 3, 1]\nRun Code Online (Sandbox Code Playgroud)\n为了理解这一点,我们需要知道 pympler 到底在检查什么。
\nmuppy.get_objects实施依赖于
gc.get_objects(),它是“收集器跟踪的所有对象的列表”( gc.is_tracked),堆栈帧除外。\n\n\n原子类型的实例\xe2\x80\x99 不会被跟踪,非原子类型的实例(容器、用户定义的对象\xe2\x80\xa6)会被跟踪。然而,可以存在一些特定于类型的优化,以抑制简单实例的垃圾收集器足迹(例如仅包含原子键和值的字典)
\n
__flags__对象。(这似乎是一个错误,因为排除所有容器对象会错过容器类型的“简单实例”,这些实例不是 GC 跟踪的。更新 应在 2019-11-12 发布的 v0.8 中修复)如果您按照上面的建议存储对象列表o2并使用以下命令检查哪些对象被占用:
def tracked(obj_list, obj):\n import gc\n return {"tracked_by_muppy": any(id(item) == id(obj) for item in obj_list),\n "gc_tracked": gc.is_tracked(obj)}\nRun Code Online (Sandbox Code Playgroud)\n你会看到:
\n空字典不受 GC 跟踪,并且由于它们仅从局部变量引用,因此 muppy 不会考虑它们:
\n tracked(o2, a) # => {\'tracked_by_muppy\': False, \'gc_tracked\': False}\nRun Code Online (Sandbox Code Playgroud)\n这个不平凡的字典d 是GC 跟踪的,因此出现在 muppy 报告中:
tracked(o2, d) # => {\'tracked_by_muppy\': True, \'gc_tracked\': True}\nRun Code Online (Sandbox Code Playgroud)\n| 归档时间: |
|
| 查看次数: |
494 次 |
| 最近记录: |