Skip to content

Commit 785b4d9

Browse files
committed
gh-158585: Don't overallocate at first PyBytesWriter_Resize()
PyBytesWriter_Resize() and PyBytesWriter_Grow() no longer overallocate when the first bytes/bytearray object is allocated. Only overallocate bytes objects at next PyBytesWriter_Resize() and PyBytesWriter_Grow() calls.
1 parent ab01d18 commit 785b4d9

2 files changed

Lines changed: 17 additions & 5 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
:c:func:`PyBytesWriter_Resize` and :c:func:`PyBytesWriter_Grow` no longer
2+
overallocate when the first bytes/bytearray object is allocated. Only
3+
overallocate bytes objects at next :c:func:`PyBytesWriter_Resize` and
4+
:c:func:`PyBytesWriter_Grow` calls. Patch by Victor Stinner.

‎Objects/bytesobject.c‎

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3755,13 +3755,15 @@ byteswriter_resize(PyBytesWriter *writer, Py_ssize_t new_size, int resize)
37553755
}
37563756

37573757
Py_ssize_t alloc = new_size;
3758-
if (resize && writer->overallocate) {
3759-
if (alloc <= (PY_SSIZE_T_MAX - alloc / OVERALLOCATE_FACTOR)) {
3760-
alloc += alloc / OVERALLOCATE_FACTOR;
3758+
if (writer->obj != NULL) {
3759+
// Overallocate the bytes object. Do not overallocate bytearray or
3760+
// if overallocation was disabled (using the private C API).
3761+
if (writer->overallocate) {
3762+
if (alloc <= (PY_SSIZE_T_MAX - alloc / OVERALLOCATE_FACTOR)) {
3763+
alloc += alloc / OVERALLOCATE_FACTOR;
3764+
}
37613765
}
3762-
}
37633766

3764-
if (writer->obj != NULL) {
37653767
if (writer->use_bytearray) {
37663768
if (PyByteArray_Resize(writer->obj, alloc)) {
37673769
#ifdef Py_DEBUG
@@ -3784,6 +3786,12 @@ byteswriter_resize(PyBytesWriter *writer, Py_ssize_t new_size, int resize)
37843786
assert(writer->obj != NULL);
37853787
}
37863788
else {
3789+
// gh-158585: Optimistic allocation strategy: don't overallocate when
3790+
// the first bytes/bytearray object is created. The bet is that the
3791+
// most common case is that a single bytes/bytearray is needed for the
3792+
// whole writer lifecycle. In that case, PyBytesWriter_Finish() doesn't
3793+
// need to truncate the bytes/bytearray object.
3794+
37873795
char *data;
37883796
if (writer->use_bytearray) {
37893797
writer->obj = PyByteArray_FromStringAndSize(NULL, alloc);

0 commit comments

Comments
 (0)