@@ -91,6 +91,10 @@ ensure_shared_on_resize(PyListObject *self)
9191#endif
9292}
9393
94+ #define LIST_SMALL_ALLOCATED 32
95+
96+ static int py_list_resize (PyListObject * self , Py_ssize_t newsize );
97+
9498/* Ensure ob_item has room for at least newsize elements, and set
9599 * ob_size to newsize. If newsize > ob_size on entry, the content
96100 * of the new slots at exit is undefined heap trash; it's the caller's
@@ -99,22 +103,37 @@ ensure_shared_on_resize(PyListObject *self)
99103 * Failure is impossible if newsize <= self.allocated on entry.
100104 * Note that self->ob_item may change, and even if newsize is less
101105 * than ob_size on entry.
106+ *
107+ * Always inlining list_resize() makes the fast path a few instructions
108+ * in each caller instead of a function call.
102109 */
103- static int
110+ static inline Py_ALWAYS_INLINE int
104111list_resize (PyListObject * self , Py_ssize_t newsize )
105112{
106- size_t new_allocated , target_bytes ;
107113 Py_ssize_t allocated = self -> allocated ;
108114
109115 /* Bypass realloc() when a previous overallocation is large enough
110116 to accommodate the newsize. If the newsize falls lower than half
111117 the allocated size, then proceed with the realloc() to shrink the list.
118+ gh-158592: do not shrink a small list, the realloc() cost is bigger
119+ than the memory we get back.
112120 */
113- if (allocated >= newsize && newsize >= (allocated >> 1 )) {
121+ if (allocated >= newsize
122+ && (newsize >= (allocated >> 1 ) || allocated <= LIST_SMALL_ALLOCATED ))
123+ {
114124 assert (self -> ob_item != NULL || newsize == 0 );
115125 Py_SET_SIZE (self , newsize );
116126 return 0 ;
117127 }
128+ return py_list_resize (self , newsize );
129+ }
130+
131+ /* Slow path of list_resize(): allocate or reallocate ob_item. */
132+ static int
133+ py_list_resize (PyListObject * self , Py_ssize_t newsize )
134+ {
135+ size_t new_allocated , target_bytes ;
136+ Py_ssize_t allocated = self -> allocated ;
118137
119138 /* This over-allocates proportional to the list size, making room
120139 * for additional growth. The over-allocation is mild, but is
@@ -136,6 +155,8 @@ list_resize(PyListObject *self, Py_ssize_t newsize)
136155 if (newsize == 0 )
137156 new_allocated = 0 ;
138157
158+ assert (newsize > allocated || new_allocated < (size_t )allocated );
159+
139160 ensure_shared_on_resize (self );
140161
141162#ifdef Py_GIL_DISABLED
0 commit comments