代码之家  ›  专栏  ›  技术社区  ›  Bob

python-为什么不可变的对象不占用相同的内存

  •  2
  • Bob  · 技术社区  · 6 年前

    我用的是微丝,但没关系

    >>> b = [None]*40
    >>> gc.collect(); gc.mem_free(); dir(); sys.modules
    101
    7008
    ['sys', '__name__', 'a', 'gc', 'b']
    {}
    >>> for i in range(40):
    ...     b[i] = (255, 0, 0)
    ...     gc.collect(); gc.mem_free();
    ...
    ...
    ...
    5
    6800
    0
    6768
    0
    6736
    0
    6704
    0
    6672
    0
    6640
    0
    6608
    0
    6576
    0
    6544
    0
    6512
    0
    6480
    0
    6448
    0
    6416
    0
    6384
    0
    6352
    0
    6320
    0
    6288
    0
    6256
    0
    6224
    0
    6192
    0
    6160
    0
    6128
    0
    6096
    0
    6064
    0
    6032
    0
    6000
    0
    5968
    0
    5936
    0
    5904
    0
    5872
    0
    5840
    0
    5808
    0
    5776
    0
    5744
    0
    5712
    0
    5680
    0
    5648
    0
    5616
    0
    5584
    0
    5552
    >>>
    

    小数字是对象的数量 gc.collect() 收集和大量的是有多少可用内存。

    (255, 0, 0) 是一个不可变的元组,它包含不可变的对象,所以为什么每次赋值后可用内存量都会减少?

    如果一个对象是不可变的,那么Python复制它有什么意义呢?
    为什么不把相同的“指针”分配给每个 b[i] ?

    更新

    我在元组中使用了更大的数字 (55555555555555555555, 55555555555555555555) 内存的使用也是一样的。

        >>> gc.collect(); gc.mem_free(); dir(); sys.modules
    5
    6368
    ['sys', '__name__', 'gc', 'i']
    {}
    >>> b = [None]*40
    >>> for i in range(40):
    ...     b[i] = (55555555555555555555,55555555555555555555)
    ...     id(b[i])
    ...     gc.collect(); gc.mem_free()
    ...
    ...
    ...
    5347968
    10
    5824
    5347136
    0
    5808
    5347312
    0
    5792
    5347456
    0
    5776
    5347536
    0
    5760
    5347552
    0
    5744
    5347696
    0
    5728
    5347712
    0
    5712
    5347984
    0
    5696
    5348176
    0
    5680
    5348192
    0
    5664
    5348208
    0
    5648
    5348224
    0
    5632
    5348240
    0
    5616
    5348256
    0
    5600
    5348272
    0
    5584
    5348288
    0
    5568
    5348608
    0
    5552
    5348640
    0
    5536
    5348656
    0
    5520
    5348672
    0
    5504
    5348688
    0
    5488
    5348704
    0
    5472
    5348720
    0
    5456
    5348736
    0
    5440
    5348848
    0
    5424
    5348864
    0
    5408
    5348880
    0
    5392
    5348896
    0
    5376
    5348912
    0
    5360
    5348928
    0
    5344
    5348944
    0
    5328
    5349104
    0
    5312
    5349120
    0
    5296
    5349136
    0
    5280
    5349152
    0
    5264
    5349168
    0
    5248
    5349184
    0
    5232
    5349200
    0
    5216
    5349216
    0
    5200
    >>>
    

    但是当我使用整数时 (55555555555555555555) ,内存使用不会随着迭代而改变。

    1 回复  |  直到 6 年前
        1
  •  4
  •   ShadowRanger    6 年前

    因为广义实习 全部的 解释器中不可变的对象是复杂的,并且添加了大量的代码,这些代码很少能保存任何有价值的东西。

    也就是说,你的代码 使用 tuple 在cpython参考解释器上。这是一个实现细节,所以每个解释器都可以在这里做出自己的决定,我猜微丝盒并没有选择这样做(可能是为了让解释器足够简单,能够在较弱的硬件上运行)。

    看起来Micropython执行缓存 int 常量,但不适用于 元组 S; 元组 s很难处理(至少在最初,cpython没有在主a s t阶段执行此操作,它只是对生成的字节代码运行一个窥视孔优化器来转换 LOAD_CONST 其次是 BUILD_TUPLE 仅使用 装入常数 结果到 装入常数 结果的 元组 )并且所涉及的额外工作可能被认为是不值得的。