Pympler摘要似乎没有意义

时间:2016-04-13 21:10:24

标签: python python-3.x memory-leaks memory-profiling

我正在与Pympler进行一些完整性检查,以确保在我尝试分析实际脚本时我理解结果,但我对结果感到有些困惑。以下是我尝试的健全性检查:

SANITY CHECK 1:我启动Python(3)控制台并执行以下操作:

from pympler import summary, muppy
sum = summary.summarize(muppy.get_objects())
summary.print_(sum)

这导致以下摘要:

                               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

如果我刚刚启动了一个新的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))

这导致以下摘要:

                         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

我以为我刚刚初始化了四个新词典(尽管3个是空的),为什么Muppy只显示了一个新词典对象的区别?此外,为什么有成千上万的新字符串和列表,更不用说整数?

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))

结果如下:

                                                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

即使列表和词典嵌套有点令人费解,但根据我的统计,我添加了5个新词典和4个新列表。

有人能解释一下Muppy是如何计算对象的吗?

1 个答案:

答案 0 :(得分:1)

1。 get_objects在新的Python会话中

summary.summarize(muppy.get_objects())返回启动期间和运行from pympler import summary, muppy时实例化的所有对象,这说明了数量众多。

2。两次get_objects调用之间的区别

2.1。我们没有创建很多新对象

请记住,由sum生成的summary.summarize()对象是在第一个快照之后创建的,该快照解释了“成千上万的新字符串和列表”。您可以通过将测试重写为以下方式来解决此问题:

from pympler import summary, muppy
o1 = muppy.get_objects()
a = {}
b = {}
c = {}
d = {'a': [0, 0, 1, 2], 't': [3, 3, 3, 1]}
o2 = muppy.get_objects()
summary.print_(summary.get_diff(summary.summarize(o1), summary.summarize(o2)))

这会将多余的差异减少到o1和其他两个对象的大列表中:

>>> for o in diff['+']:
...     print("%s - %s" % (type(o), o if len(o) < 10 else "long list"))
...
<class 'str'> - o2
<class 'list'> - long list
<class 'dict'> - {'a': [0, 0, 1, 2], 't': [3, 3, 3, 1]}
<class 'list'> - ['o2', 'muppy', 'get_objects']
<class 'list'> - [0, 0, 1, 2]
<class 'list'> - [3, 3, 3, 1]

2.2。创建和报告的字典数量不匹配

要了解这一点,我们需要知道pympler到底在检查什么。

muppy.get_objects实现relies

  • Python的gc.get_objects(),它是“收集器跟踪的所有对象的列表”(gc.is_tracked),但堆栈框架除外。
      不会跟踪原子类型的

    实例,而不会跟踪非原子类型的实例(容器,用户定义的对象……)。但是,可以提供一些特定于类型的优化,以抑制简单实例的垃圾收集器占用空间(例如,仅包含原子键和值的字典

  • 然后,它添加从步骤1中获得的对象引用的对象(gc.get_referents,但是excluding“容器对象”-类型为{{ 1}}。 (这似乎是一个错误,因为排除所有容器对象会错过未通过GC跟踪的容器类型的“简单实例”。)

如果您按照上述建议存储对象列表__flags__,并检查使用了哪些对象:

o2

您会看到:

  • 空dict不受GC跟踪,并且由于它们仅从局部变量中引用,因此muppy不能解释它们:

    def tracked(obj_list, obj):
        import gc
        return {"tracked_by_muppy": any(id(item) == id(obj) for item in obj_list),
                "gc_tracked": gc.is_tracked(obj)}
    
  • 简单的字典tracked(o2, a) # => {'tracked_by_muppy': False, 'gc_tracked': False} 是GC跟踪的,因此出现在muppy报告中:

    d