numpy空数组为何存在96字节开销?存储内容及源码位置问询
Why does a NumPy array have a 96-byte overhead?
Great question! Let's unpack this—understanding the overhead of NumPy arrays helps you grasp how the library manages memory under the hood.
What's stored in those 96 bytes?
That 96-byte overhead comes from the PyArrayObject struct, the C-level blueprint for every NumPy array. Even empty arrays need this metadata to track their state, and on 64-bit systems (the modern standard), this struct totals exactly 96 bytes. Here's a breakdown of each component:
- Python Object Header (
PyObject_HEAD): 16 bytes. Every Python object starts with this—it holds the reference count (ob_refcnt) and a pointer to the object's type (ob_type), which CPython uses for memory management and type checking. - Array Dimension (
ndim): 4-byte integer (padded to 8 bytes for memory alignment). Stores the number of dimensions (0 for an empty array, 1 for a 1D array, etc.). - Item Size (
itemsize): 8 bytes. The number of bytes each element in the array takes up (0 for an empty array, but the field still reserves space). - Shape Pointer (
shape): 8-byte pointer. Points to an array that stores the size of each dimension (for an empty array, this might point to a placeholder or empty structure, but the pointer itself occupies space). - Strides Pointer (
strides): 8-byte pointer. Points to an array that tracks how many bytes you need to jump to move to the next element in each dimension. - Data Type Descriptor (
descr): 8-byte pointer. Points to aPyArray_Descrobject that defines the array's data type (e.g.,float64for the default empty array). - Data Buffer Pointer (
data): 8-byte pointer. Points to the actual memory where array elements are stored. For an empty array, this isNULL, but the pointer still takes up space. - Base Object (
base): 8-byte pointer. If the array borrows memory from another Python object (like a list or another array), this holds a reference to that object to prevent it from being garbage collected early. Empty arrays set this toNULL. - Flags (
flags): 4-byte integer (padded to 8 bytes for alignment). Stores flags that describe array properties: whether it's writable, uses C-style row-major order, is memory-aligned, etc. - Offset (
offset): 8 bytes. The number of bytes to skip from thedatapointer to reach the first element (0 for empty arrays). - Weak Reference List (
weakreflist): 8-byte pointer. Supports Python's weak reference mechanism by pointing to a list of weak references to the array.
Adding all these up (16 + 8*10) gives you exactly 96 bytes for the struct itself.
Where is this implemented in the source code?
The core definition lives in NumPy's C source files:
- Struct Definition: The
PyArrayObjectstruct is defined innumpy/core/include/numpy/ndarraytypes.h. This is where all the metadata fields are laid out. - Array Initialization: When you call
np.array([]), it triggers thePyArray_Newfunction innumpy/core/src/multiarray/arrayobject.c. This function allocates memory for thePyArrayObjectstruct and initializes all its fields (setting default types, empty pointers, etc.). - Size Reporting: The
sys.getsizeof()function relies on thetp_basicsizeattribute of thePyArray_Typeobject (also defined inarrayobject.c). This attribute is set tosizeof(PyArrayObject), which is 96 bytes on 64-bit systems—that's why you see that number when you callsys.getsizeof(np.array([])).
内容的提问来源于stack exchange,提问作者Evan Carroll
相关产品推荐
相关产品推荐

