Why Python Caches Small Integers and How the Internal Object Pools Work
This article explains Python's integer object implementation, detailing how small integers are cached in a fixed‑size pool, how larger integers are managed through a dynamic PyIntBlock structure, and why using xrange (or range in Python 3) avoids memory bloat.
Python Integer Object Implementation Overview
The following explains the internal mechanisms CPython uses to create and manage integer objects, including the small‑integer cache, the general integer pool, and the memory‑allocation strategy.
>> a = 1
>>> b = 1
>>> id(a) == id(b)
True
>>> c = 257
>>> d = 257
>>> id(c) == id(d)
FalsePyIntObject Structure
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;Constructor Functions
PyAPI_FUNC(PyObject *) PyInt_FromString(char *, char **);
#ifdef Py_USING_UNICODE
PyAPI_FUNC(PyObject *) PyInt_FromUnicode(Py_UNICODE *, Py_ssize_t, int);
#endif
PyAPI_FUNC(PyObject *) PyInt_FromLong(long);
PyAPI_FUNC(PyObject *) PyInt_FromSize_t(size_t);
PyAPI_FUNC(PyObject *) PyInt_FromSsize_t(Py_ssize_t);All constructors ultimately call PyInt_FromLong, which contains the core allocation logic.
PyInt_FromLong Implementation
PyObject *
PyInt_FromLong(long ival)
{
register PyIntObject *v;
/* If the value is within the small‑integer range, return the cached object */
if (-(NSMALLNEGINTS) <= ival && ival < NSMALLPOSINTS) {
v = small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v);
return (PyObject *)v;
}
/* Allocate from the free list or create a new block */
if (free_list == NULL) {
if ((free_list = fill_free_list()) == NULL)
return NULL;
}
v = free_list;
free_list = (PyIntObject *)Py_TYPE(v);
PyObject_INIT(v, &PyInt_Type);
v->ob_ival = ival;
return (PyObject *)v;
}Small‑Integer Object Pool
#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS 257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS 5
#endif
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
#endifThe pool is a pointer array covering the range [-5, 257); each entry points to a unique PyIntObject. Objects in this range are created once during interpreter startup and reused, which explains the True result for a and b above.
General Integer Object Pool (PyIntBlock)
#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */
#define BHEAD_SIZE 8 /* Enough for a 64‑bit pointer */
#define N_INTOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyIntObject))
struct _intblock {
struct _intblock *next;
PyIntObject objects[N_INTOBJECTS];
};
typedef struct _intblock PyIntBlock;Two static pointers keep track of the allocation state:
static PyIntBlock *block_list = NULL;
static PyIntObject *free_list = NULL;Block Allocation (fill_free_list)
static PyIntObject *fill_free_list(void)
{
PyIntObject *p, *q;
PyIntBlock *new_block = (PyIntObject *)PyMem_MALLOC(sizeof(PyIntBlock));
if (new_block == NULL)
return (PyIntObject *)PyErr_NoMemory();
/* Link the new block into the block list */
new_block->next = block_list;
block_list = new_block;
/* Build a singly‑linked free list from the objects array */
p = &new_block->objects[0];
q = p + N_INTOBJECTS;
while (--q > p) {
Py_TYPE(q) = (struct _typeobject *)q - 1; /* reuse ob_type as next pointer */
}
Py_TYPE(p) = NULL;
return p + N_INTOBJECTS - 1; /* return head of the free list */
}When the free list is exhausted, a new PyIntBlock is allocated, linked into block_list, and its objects are chained together to form a new free list.
Deallocation (int_dealloc)
static void int_dealloc(PyIntObject *v)
{
if (PyInt_CheckExact(v)) {
Py_TYPE(v) = (struct _typeobject *)free_list;
free_list = v;
} else {
((struct _typeobject *)Py_TYPE(v))->tp_free((PyObject *)v);
}
}Exact integer objects are returned to the free list; other types use their type‑specific deallocator.
Practical Implications
Because PyIntBlock memory is never released before interpreter shutdown, generating large ranges with range(100000) in Python 2 can retain a substantial amount of memory. Using xrange (or range in Python 3, which behaves like xrange) avoids this issue.
In summary, CPython optimizes integer handling by caching a small range of frequently used values and by allocating larger integers in blocks that are reclaimed via a free‑list mechanism, ensuring fast object creation while managing memory efficiently.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
