Python @dataclasses 中 pympler.asizeof 测量结果受参数顺序影响的原因?
核心原因
pympler的asizesof函数默认会去重统计已经计算过的对象,避免共享对象被重复计算大小,入参顺序决定了共享对象被第一次统计的时机,进而影响每个入参最终的数值。
具体逻辑说明
asizesof会按入参顺序逐个处理对象,统计对象总大小时会递归遍历它引用的所有子对象,所有已经被统计过的对象(包括前面入参的对象本身、它们引用的子对象)不会再被计入后续对象的大小中。- 你的测试场景里存在大量共享对象:整数1、2是Python驻留的全局唯一小整数,
test_1和test_2的属性都引用了这两个相同的对象。 - 两个测试类的内存结构不同:
- 带
__slots__的TEST1实例没有独立的__dict__属性,自身基础内存更小 - 不带
__slots__的TEST2实例自带存储属性的__dict__字典,自身基础内存更大,__dict__本身也需要计入总大小
- 带
补充:这个去重逻辑是有意设计的,如果你把
asizesof返回的所有值加总,总和就是这组对象的总内存占用(共享部分只算一次),总大小不会受入参顺序影响,受影响的只是每个单独入参的统计值。
对应测试结果解释
举两组结果对比即可验证逻辑:
- 调用
asizesof(test_1, test_2)返回(112, 264)- 先处理
test_1:第一次统计到整数1、2,这两个的大小会被计入test_1的总大小,最终得到112 - 后处理
test_2:整数1、2已经被统计过不再重复计算,只统计test_2自身和它的__dict__大小,得到264
- 先处理
- 调用
asizesof(test_2, test_1)返回(328, 48)- 先处理
test_2:第一次统计到整数1、2、test_2本身和它的__dict__,全部加起来得到328 - 后处理
test_1:整数1、2已经被统计过,只需要算test_1自身的基础大小,得到48
- 先处理
解决方案
如果你需要统计每个对象的独立全量大小,避免入参之间互相影响,不要把多个对象放在同一个asizesof调用里,逐个单独调用asizeof.asizeof()即可,比如:
print(asizeof.asizeof(test_1), asizeof.asizeof(test_2))
这样每次统计都会从零开始计数,不会出现顺序影响结果的问题。
内容的提问来源于stack exchange,提问作者tomm
相关产品推荐
相关产品推荐

