【问题标题】:Numpy array memory managementNumpy 数组内存管理
【发布时间】:2013-01-29 16:18:10
【问题描述】:

我有一个关于 Numpy 数组内存管理的问题。假设我使用以下内容从缓冲区创建一个 numpy 数组:

>>> s = "abcd"
>>> arr = numpy.frombuffer(buffer(s), dtype = numpy.uint8)
>>> arr.flags
  C_CONTIGUOUS : True
  F_CONTIGUOUS : True
  OWNDATA : False
  WRITEABLE : False
  ALIGNED : True
  UPDATEIFCOPY : False
>>> del s # What happens to arr?

在上述情况下,'arr' 是否包含对 's' 的引用?如果我删除“s”,这是否会释放为“s”分配的内存,从而使“arr”可能引用未分配的内存?

我还有一些其他问题:

  • 如果这是有效的,Python 如何知道何时释放 's' 分配的内存? gc.get_referrents(arr) 函数似乎没有显示“arr”包含对“s”的引用。
  • 如果这是无效的,我如何注册对 's' 的引用到 'arr' 中,以便 Python GC 在对它的所有引用都消失后自动获取 's'?

【问题讨论】:

    标签: arrays memory numpy


    【解决方案1】:

    为了补充@seberg 的评论:

        import ctypes
        import sys
    
        import numpy as np
    
        b = bytearray([1, 2, 3])
        b_addr = id(b)
        print(sys.getrefcount(b) - 1, ctypes.c_long.from_address(b_addr).value)  # => 1 1
        a1 = np.frombuffer(b, dtype=np.int8)
        assert b[0] == a1[0]
        b[0] = b[0] + 1
        assert b[0] == a1[0]
        print(sys.getrefcount(b) - 1, ctypes.c_long.from_address(b_addr).value)  # => 2 2
        a2 = np.frombuffer(b, dtype=np.int8)
        print(sys.getrefcount(b) - 1, ctypes.c_long.from_address(b_addr).value)  # => 3 3
        del a2
        print(sys.getrefcount(b) - 1, ctypes.c_long.from_address(b_addr).value)  # => 2 2
        del b
        print(ctypes.c_long.from_address(b_addr).value)  # => 1
        del a1
        print(ctypes.c_long.from_address(b_addr).value)  # => 0
    

    sys.getrefcount(b) 返回更高的值“因为它包含(临时)引用作为 getrefcount() 的参数”

    【讨论】:

      【解决方案2】:

      以下内容应该稍微澄清一下:

      >>> s = 'abcd'
      >>> arr = np.frombuffer(buffer(s), dtype='uint8')
      >>> arr.base
      <read-only buffer for 0x03D1BA60, size -1, offset 0 at 0x03D1BA00>
      >>> del s
      >>> arr.base
      <read-only buffer for 0x03D1BA60, size -1, offset 0 at 0x03D1BA00>
      

      在第一种情况下,del s 无效,因为数组指向的是从它创建的buffer,它在其他任何地方都没有引用。

      >>> t = buffer('abcd')
      >>> arr = np.frombuffer(t, dtype='uint8')
      >>> arr.base
      <read-only buffer for 0x03D1BA60, size -1, offset 0 at 0x03C8D920>
      >>> arr.base is t
      True
      >>> del t
      >>> arr.base
      <read-only buffer for 0x03D1BA60, size -1, offset 0 at 0x03C8D920>
      

      在第二种情况下,当您del t 时,您摆脱了指向buffer 对象的变量t,但是因为该数组仍然具有对同一个buffer 的引用,所以它没有被删除.虽然我不确定如何检查它,但如果您现在 del arrbuffer 对象应该会丢失其最后一个引用并自动被垃圾回收。

      【讨论】:

      • 您可以在 CPython 中使用 sys.getrefcount 来观察 s 在这两种情况下的引用计数增加。没关系,它当然可以工作。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-28
      • 2012-03-07
      • 1970-01-01
      相关资源
      最近更新 更多