6

我有一个关于 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'?
4

2 回答 2

6

The following should clarify things a little:

>>> 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>

In the first case del s has no effect, because what the array is pointing to is a buffer created from it, which is not referenced anywhere else.

>>> 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>

In the second case, when you del t, you get rid of the variable t pointing to the buffer object, but because the array still has a reference to that same buffer, it is not deleted. While I am not sure how to check it, if you now del arr, the buffer object should lose its last reference and be automatically garbage-collected.

于 2013-02-14T01:02:31.743 回答
0

为了补充@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() 的参数”

于 2021-08-07T10:57:42.963 回答