Numpy数组封装列表对象的内存占用异常及计算方法咨询
首先,你遇到的核心问题是混淆了容器对象本身的内存占用和它所引用的所有数据的总内存占用,这也是Python中内存计算的常见误区之一。
为什么当前的内存测量结果不变?
我们逐个拆解你用到的工具:
sys.getsizeof()
这个函数只返回对象自身的内存大小,不会递归计算它引用的其他对象的内存。比如你创建的列表a1、a2,本质上是存储了几个指针(指向numpy数组、字符串)的容器。在64位系统中,每个指针占8字节,加上列表自身的结构开销,初始的小列表大小固定为88字节很正常——不管你指针指向的numpy数组是2MB还是600KB,列表本身只需要存这几个指针,大小不会变。numpy数组的
nbytes属性
对于普通的数值型numpy数组(比如你创建的x、y),nbytes确实能正确返回数据本身的内存大小,这部分是没问题的。但当你创建dtype=object的numpy数组(比如a3、a4)时,这个数组本质上是存储对象指针的数组,nbytes只计算这些指针占用的字节数(比如3个指针就是3×8=24字节),完全不涉及指针指向的numpy数组、字符串的内存。
正确的内存计算方法
要得到包含所有数据的总内存占用,你需要使用能递归遍历所有引用对象的工具,而你已经导入的pympler.asizeof就是干这个的!
比如在你的代码中试试这些操作:
print(asizeof(a1)) # 会包含x的2MB+列表+字符串的总内存 print(asizeof(a2)) # 会包含y的600KB+列表+字符串的总内存,明显比a1小
asizeof会递归计算列表、numpy数组、字符串等所有关联对象的内存总和,这样你就能看到不同数据量的真实内存差异了。
另外,如果你不想用第三方库,也可以手动估算:
- 容器本身的大小(
sys.getsizeof(容器)) - 加上每个引用对象的内存:比如numpy数组用
x.nbytes + sys.getsizeof(x)(因为numpy数组本身的结构也占用一点内存),字符串用sys.getsizeof(字符串)(注意Python会缓存短字符串,重复的字符串不会重复占用内存)
但手动估算容易漏算,还是asizeof更准确可靠。
额外说明
你修改列表内容(比如把a2改成[[y重复100次], '1','2'])后,sys.getsizeof(a2)还是88,是因为a2本身只存储3个引用:一个指向子列表的指针,两个指向字符串的指针。子列表里的100个y引用,属于子列表的内存,a2本身的大小不受影响——你需要用asizeof(a2)才能看到包含子列表和所有y引用的总内存。
内容的提问来源于stack exchange,提问作者Piyush

