我有一个对象,需要用0-3个字符串(在20种可能性中)进行“标记”;这些值都是唯一的,顺序无关紧要。唯一需要对标签执行的操作就是检查是否存在特定的标签(specific_value in self.tags
)。
但是,一次在内存中存在大量的这些对象,以至于它突破了我的旧计算机RAM的极限。因此节省几个字节就可以加起来。
每个对象上的标签太少了,我怀疑查找时间会变得很重要。但是:在这里使用元组和Frozenset之间有内存差异吗?还有其他真正的理由要使用另一个吗?
答案 0 :(得分:4)
sys.getsizeof
似乎是您想要的stdlib
选项...但是我对您的整个用例感到不满意
import sys
t = ("foo", "bar", "baz")
f = frozenset(("foo","bar","baz"))
print(sys.getsizeof(t))
print(sys.getsizeof(f))
https://docs.python.org/3.7/library/sys.html#sys.getsizeof
所有内置对象都将返回正确的结果,但是对于第三方扩展,这不一定成立,因为它是特定于实现的。
...所以请不要对这种解决方案感到不适
编辑:显然@TimPeters的答案更正确...
答案 1 :(得分:3)
音色非常紧凑。集合基于哈希表,并且依赖于具有“空”插槽以减少哈希冲突的可能性。
对于最新版本的CPython,sys._debugmallocstats()
显示许多可能有趣的信息。在64位Python 3.7.3下:
>>> from sys import _debugmallocstats as d
>>> tups = [tuple("abc") for i in range(1000000)]
tuple("abc")
创建一个由3个1个字符的字符串('a', 'b', 'c')
组成的元组。这是我几乎要编辑的所有输出:
>>> d()
Small block threshold = 512, in 64 size classes.
class size num pools blocks in use avail blocks
----- ---- --------- ------------- ------------
...
8 72 17941 1004692 4
自从我们创建了一百万个元组以来,我们非常希望使用1004692个块的size类是我们想要的;-)每个块占用72个字节。
切换到冻结集,输出显示,每个冻结集消耗224个字节,比原来多3倍:
>>> tups = [frozenset(t) for t in tups]
>>> d()
Small block threshold = 512, in 64 size classes.
class size num pools blocks in use avail blocks
----- ---- --------- ------------- ------------
...
27 224 55561 1000092 6
在这种情况下,您得到的另一个答案碰巧给出了相同的结果:
>>> import sys
>>> sys.getsizeof(tuple("abc"))
72
>>> sys.getsizeof(frozenset(tuple("abc")))
224
虽然这通常是正确的,但并非总是如此,因为对象可能需要比实际需要的分配个字节更多的字节,才能满足硬件对齐要求。 getsizeof()
对此一无所知,但是_debugmallocstats()
显示了Python的小对象分配器实际需要使用的字节数。
例如,
>>> sys.getsizeof("a")
50
在32位的盒子上,实际上需要使用52个字节来提供4个字节的对齐方式。在64位设备上,当前需要8字节对齐,因此需要使用56个字节。在Python 3.8(尚未发布)下,在64位盒上需要16字节对齐,并且将需要使用64字节。
但是忽略所有这些,元组将总是需要比具有相同数量的元素的任何形式的set更少的内存,甚至比具有相同数量的元素的列表所需要的内存更少。
答案 2 :(得分:2)
如果您想节省内存,请考虑
dict
映射。如果没有标记,则词典中没有条目。答案 3 :(得分:1)
`如果用recordclass库中的类型替换元组,有可能减少内存:
>>> from recordclass import make_arrayclass
>>> Triple = make_arrayclass("Triple", 3)
>>> from sys import getsizeof as sizeof
>>> sizeof(Triple("ab","cd","ef"))
40
>>> sizeof(("ab","cd","ef"))
64
差异等于sizeof(PyHC_Head)
+ sizeof(Py_ssize_t)
。
P.S .:在64位Python 3.8上测量数字。