{
  "__type": "IngestedDoc",
  "__tag": 4010,
  "_content": {},
  "_ordered_sections": [],
  "item_file": null,
  "item_line": null,
  "item_type": null,
  "aliases": [],
  "example_section_data": {
    "__type": "Section",
    "__tag": 4015,
    "children": [],
    "title": [],
    "level": 0,
    "target": null
  },
  "see_also": [],
  "signature": null,
  "references": null,
  "qa": "reference:c-api:data_memory",
  "arbitrary": [
    {
      "__type": "Section",
      "__tag": 4015,
      "children": [
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "The "
            },
            {
              "__type": "CrossRef",
              "__tag": 4002,
              "value": "numpy.ndarray",
              "reference": {
                "__type": "RefInfo",
                "__tag": 4000,
                "module": "numpy",
                "version": "*",
                "kind": "api",
                "path": "numpy:ndarray"
              },
              "kind": "module"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " is a python class. It requires additional memory allocations to hold "
            },
            {
              "__type": "InlineRole",
              "__tag": 4003,
              "value": "numpy.ndarray.strides",
              "domain": null,
              "role": null,
              "inventory": null
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", "
            },
            {
              "__type": "InlineRole",
              "__tag": 4003,
              "value": "numpy.ndarray.shape",
              "domain": null,
              "role": null,
              "inventory": null
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " and "
            },
            {
              "__type": "InlineRole",
              "__tag": 4003,
              "value": "numpy.ndarray.data",
              "domain": null,
              "role": null,
              "inventory": null
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " attributes. These attributes are specially allocated after creating the python object in "
            },
            {
              "__type": "InlineRole",
              "__tag": 4003,
              "value": "~object.__new__",
              "domain": null,
              "role": "meth",
              "inventory": null
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ". The "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "strides"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " and "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "shape"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " are stored in a piece of memory allocated internally."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "The "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "data"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " allocation used to store the actual array values (which could be pointers in the case of "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "object"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " arrays) can be very large, so NumPy has provided interfaces to manage its allocation and release. This document details how those interfaces work."
            }
          ]
        }
      ],
      "title": [
        {
          "__type": "Text",
          "__tag": 4046,
          "value": "Memory management in NumPy"
        }
      ],
      "level": 0,
      "target": "data_memory"
    },
    {
      "__type": "Section",
      "__tag": 4015,
      "children": [
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Since version 1.7.0, NumPy has exposed a set of "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyDataMem_*"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " functions ("
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyDataMem_NEW"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyDataMem_FREE"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyDataMem_RENEW"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ") which are backed by "
            },
            {
              "__type": "InlineRole",
              "__tag": 4003,
              "value": "alloc",
              "domain": null,
              "role": null,
              "inventory": null
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", "
            },
            {
              "__type": "InlineRole",
              "__tag": 4003,
              "value": "free",
              "domain": null,
              "role": null,
              "inventory": null
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", "
            },
            {
              "__type": "InlineRole",
              "__tag": 4003,
              "value": "realloc",
              "domain": null,
              "role": null,
              "inventory": null
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " respectively."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Since those early days, Python also improved its memory management capabilities, and began providing various "
            },
            {
              "__type": "InlineRole",
              "__tag": 4003,
              "value": "management policies <memoryoverview>",
              "domain": null,
              "role": "ref",
              "inventory": null
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " beginning in version 3.4. These routines are divided into a set of domains, each domain has a "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyMemAllocatorEx"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " structure of routines for memory management. Python also added a "
            },
            {
              "__type": "CrossRef",
              "__tag": 4002,
              "value": "tracemalloc",
              "reference": {
                "__type": "LocalRef",
                "__tag": 4022,
                "kind": "docs",
                "path": "release:1.13.0-notes"
              },
              "kind": "exists"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " module to trace calls to the various routines. These tracking hooks were added to the NumPy "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyDataMem_*"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " routines."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "NumPy added a small cache of allocated memory in its internal "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "npy_alloc_cache"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "npy_alloc_cache_zero"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", and "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "npy_free_cache"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " functions. These wrap "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "alloc"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "alloc-and-memset(0)"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " and "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "free"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " respectively, but when "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "npy_free_cache"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " is called, it adds the pointer to a short list of available blocks marked by size. These blocks can be re-used by subsequent calls to "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "npy_alloc*"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", avoiding memory thrashing."
            }
          ]
        }
      ],
      "title": [
        {
          "__type": "Text",
          "__tag": 4046,
          "value": "Historical overview"
        }
      ],
      "level": 1,
      "target": null
    },
    {
      "__type": "Section",
      "__tag": 4015,
      "children": [
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Users may wish to override the internal data memory routines with ones of their own. Since NumPy does not use the Python domain strategy to manage data memory, it provides an alternative set of C-APIs to change memory routines. There are no Python domain-wide strategies for large chunks of object data, so those are less suited to NumPy's needs. User who wish to change the NumPy data memory management routines can use "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyDataMem_SetHandler"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", which uses a "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyDataMem_Handler"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " structure to hold pointers to functions used to manage the data memory. The calls are still wrapped by internal routines to call "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyTraceMalloc_Track"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyTraceMalloc_Untrack"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ". Since the functions may change during the lifetime of the process, each "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "ndarray"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " carries with it the functions used at the time of its instantiation, and these will be used to reallocate or free the data memory of the instance."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "For an example of setting up and using the PyDataMem_Handler, see the test in "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "numpy/_core/tests/test_mem_policy.py"
            }
          ]
        }
      ],
      "title": [
        {
          "__type": "Text",
          "__tag": 4046,
          "value": "Configurable memory routines in NumPy (NEP 49)"
        }
      ],
      "level": 1,
      "target": null
    },
    {
      "__type": "Section",
      "__tag": 4015,
      "children": [
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "A rare but useful technique is to allocate a buffer outside NumPy, use "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyArray_NewFromDescr"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " to wrap the buffer in a "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "ndarray"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", then switch the "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "OWNDATA"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " flag to true. When the "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "ndarray"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " is released, the appropriate function from the "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "ndarray"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "'s "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyDataMem_Handler"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " should be called to free the buffer. But the "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyDataMem_Handler"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " field was never set, it will be "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "NULL"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ". For backward compatibility, NumPy will call "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "free()"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " to release the buffer. If "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "NUMPY_WARN_IF_NO_MEM_POLICY"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " is set to "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "1"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ", a warning will be emitted. The current default is not to emit a warning, this may change in a future version of NumPy."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "A better technique would be to use a "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "PyCapsule"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " as a base object:"
            }
          ]
        },
        {
          "__type": "Code",
          "__tag": 4050,
          "value": "/* define a PyCapsule_Destructor, using the correct deallocator for buff */\nvoid free_wrap(void *capsule){\n    void * obj = PyCapsule_GetPointer(capsule, PyCapsule_GetName(capsule));\n    free(obj); \n};\n\n/* then inside the function that creates arr from buff */\n...\narr = PyArray_NewFromDescr(... buf, ...);\nif (arr == NULL) {\n    return NULL;\n}\ncapsule = PyCapsule_New(buf, \"my_wrapped_buffer\",\n                        (PyCapsule_Destructor)&free_wrap);\nif (PyArray_SetBaseObject(arr, capsule) == -1) {\n    Py_DECREF(arr);\n    return NULL;\n}\n...",
          "execution_status": null
        }
      ],
      "title": [
        {
          "__type": "Text",
          "__tag": 4046,
          "value": "What happens when deallocating if there is no policy set"
        }
      ],
      "level": 1,
      "target": null
    },
    {
      "__type": "Section",
      "__tag": 4015,
      "children": [
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "The builtin "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "tracemalloc"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " module can be used to track allocations inside NumPy. NumPy places its CPU memory allocations into the  "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "np.lib.tracemalloc_domain"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": " domain. For additional information, check: https://docs.python.org/3/library/tracemalloc.html."
            }
          ]
        },
        {
          "__type": "Paragraph",
          "__tag": 4045,
          "children": [
            {
              "__type": "Text",
              "__tag": 4046,
              "value": "Here is an example on how to use "
            },
            {
              "__type": "InlineCode",
              "__tag": 4051,
              "value": "np.lib.tracemalloc_domain"
            },
            {
              "__type": "Text",
              "__tag": 4046,
              "value": ":"
            }
          ]
        },
        {
          "__type": "Code",
          "__tag": 4050,
          "value": "\"\"\"\n   The goal of this example is to show how to trace memory\n   from an application that has NumPy and non-NumPy sections.\n   We only select the sections using NumPy related calls.\n\"\"\"\n\nimport tracemalloc\nimport numpy as np\n\n# Flag to determine if we select NumPy domain\nuse_np_domain = True\n\nnx = 300\nny = 500\n\n# Start to trace memory\ntracemalloc.start()\n\n# Section 1\n# ---------\n\n# NumPy related call\na = np.zeros((nx,ny))\n\n# non-NumPy related call\nb = [i**2 for i in range(nx*ny)]\n\nsnapshot1 = tracemalloc.take_snapshot()\n# We filter the snapshot to only select NumPy related calls\nnp_domain = np.lib.tracemalloc_domain\ndom_filter = tracemalloc.DomainFilter(inclusive=use_np_domain,\n                                      domain=np_domain)\nsnapshot1 = snapshot1.filter_traces([dom_filter])\ntop_stats1 = snapshot1.statistics('traceback')\n\nprint(\"================ SNAPSHOT 1 =================\")\nfor stat in top_stats1:\n    print(f\"{stat.count} memory blocks: {stat.size / 1024:.1f} KiB\")\n    print(stat.traceback.format()[-1])\n\n# Clear traces of memory blocks allocated by Python\n# before moving to the next section.\ntracemalloc.clear_traces()\n\n# Section 2\n#----------\n\n# We are only using NumPy\nc = np.sum(a*a)\n\nsnapshot2 = tracemalloc.take_snapshot()\ntop_stats2 = snapshot2.statistics('traceback')\n\nprint()\nprint(\"================ SNAPSHOT 2 =================\")\nfor stat in top_stats2:\n    print(f\"{stat.count} memory blocks: {stat.size / 1024:.1f} KiB\")\n    print(stat.traceback.format()[-1])\n\ntracemalloc.stop()\n\nprint()\nprint(\"============================================\")\nprint(\"\\nTracing Status : \", tracemalloc.is_tracing())\n\ntry:\n    print(\"\\nTrying to Take Snapshot After Tracing is Stopped.\")\n    snap = tracemalloc.take_snapshot()\nexcept Exception as e:\n    print(\"Exception : \", e)",
          "execution_status": null
        }
      ],
      "title": [
        {
          "__type": "Text",
          "__tag": 4046,
          "value": "Example of memory tracing with "
        },
        {
          "__type": "InlineCode",
          "__tag": 4051,
          "value": "np.lib.tracemalloc_domain"
        }
      ],
      "level": 1,
      "target": null
    }
  ],
  "local_refs": []
}