Relax, it’s all good! To kick things off, what are memory allocators? They’re basically responsible for managing how Python allocates memory when you create objects or perform other operations that require memory allocation. By default, Python uses a built-in memory allocator called pymalloc.
But sometimes, you might want to customize this behavior for various reasons (like performance optimization). Now, the rules of engagement. If you call these functions after Python has finished initializing (after “Py_InitializeFromConfig()” has been called), then you must wrap the existing allocator. Substituting the current allocator for some other arbitrary one is not supported.
This means that if you want to customize your memory allocator, you need to do it before Python starts up.
But wait! There’s a catch. If you try to cast the memory returned by these functions as a Python object when intercepting the allocating functions in this domain (which is what we call it when we’re customizing our memory allocator), there’s no guarantee that it will work. So, be careful out there! Now, some of the functions you can use to customize your memory allocators.
One such function is PyObject_Malloc(). This function is part of the Stable ABI (Application Binary Interface), which means that its behavior won’t change between Python releases. It takes a size parameter and returns a pointer to the allocated memory. But remember, The GIL must be held when using these functions.
If you don’t know what the GIL is, it stands for Global Interpreter Lock (or “Gilbert” if you prefer). Basically, it’s a lock that Python uses to ensure thread safety in multi-threaded environments. So, make sure you hold onto your Gilberts tightly! Just remember to wrap the existing allocator and don’t try to cast your customized memory as a Python object unless you know what you’re doing!