Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fd24b32

Browse files
committed
Issue #4445: save 3 bytes of memory (on average) per bytes allocation.
(This is a forward port of r67601).
1 parent 17fe364 commit fd24b32

2 files changed

Lines changed: 23 additions & 10 deletions

File tree

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ What's New in Python 3.1 alpha 0
1212
Core and Builtins
1313
-----------------
1414

15+
- Issue #4445: Replace "sizeof(PyBytesObject)" with
16+
"offsetof(PyBytesObject, ob_sval) + 1" when allocating memory for
17+
bytes instances. On a typical machine this saves 3 bytes of memory
18+
(on average) per allocation of a bytes instance.
19+
1520
- Issue #4533: File read operation was dreadfully slow due to a slowly
1621
growing read buffer. Fixed by using the same growth rate algorithm as
1722
Python 2.x.

Objects/bytesobject.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "Python.h"
66

77
#include "bytes_methods.h"
8+
#include <stddef.h>
89

910
static Py_ssize_t
1011
_getbuffer(PyObject *obj, Py_buffer *view)
@@ -31,6 +32,14 @@ int null_strings, one_strings;
3132
static PyBytesObject *characters[UCHAR_MAX + 1];
3233
static PyBytesObject *nullstring;
3334

35+
/* PyBytesObject_SIZE gives the basic size of a string; any memory allocation
36+
for a string of length n should request PyBytesObject_SIZE + n bytes.
37+
38+
Using PyBytesObject_SIZE instead of sizeof(PyBytesObject) saves
39+
3 bytes per string allocation on a typical system.
40+
*/
41+
#define PyBytesObject_SIZE (offsetof(PyBytesObject, ob_sval) + 1)
42+
3443
/*
3544
For both PyBytes_FromString() and PyBytes_FromStringAndSize(), the
3645
parameter `size' denotes number of characters to allocate, not counting any
@@ -83,14 +92,14 @@ PyBytes_FromStringAndSize(const char *str, Py_ssize_t size)
8392
return (PyObject *)op;
8493
}
8594

86-
if (size > PY_SSIZE_T_MAX - sizeof(PyBytesObject)) {
95+
if (size > PY_SSIZE_T_MAX - PyBytesObject_SIZE) {
8796
PyErr_SetString(PyExc_OverflowError,
8897
"byte string is too large");
8998
return NULL;
9099
}
91100

92101
/* Inline PyObject_NewVar */
93-
op = (PyBytesObject *)PyObject_MALLOC(sizeof(PyBytesObject) + size);
102+
op = (PyBytesObject *)PyObject_MALLOC(PyBytesObject_SIZE + size);
94103
if (op == NULL)
95104
return PyErr_NoMemory();
96105
PyObject_INIT_VAR(op, &PyBytes_Type, size);
@@ -117,7 +126,7 @@ PyBytes_FromString(const char *str)
117126

118127
assert(str != NULL);
119128
size = strlen(str);
120-
if (size > PY_SSIZE_T_MAX - sizeof(PyBytesObject)) {
129+
if (size > PY_SSIZE_T_MAX - PyBytesObject_SIZE) {
121130
PyErr_SetString(PyExc_OverflowError,
122131
"byte string is too long");
123132
return NULL;
@@ -138,7 +147,7 @@ PyBytes_FromString(const char *str)
138147
}
139148

140149
/* Inline PyObject_NewVar */
141-
op = (PyBytesObject *)PyObject_MALLOC(sizeof(PyBytesObject) + size);
150+
op = (PyBytesObject *)PyObject_MALLOC(PyBytesObject_SIZE + size);
142151
if (op == NULL)
143152
return PyErr_NoMemory();
144153
PyObject_INIT_VAR(op, &PyBytes_Type, size);
@@ -746,13 +755,12 @@ string_repeat(register PyBytesObject *a, register Py_ssize_t n)
746755
return (PyObject *)a;
747756
}
748757
nbytes = (size_t)size;
749-
if (nbytes + sizeof(PyBytesObject) <= nbytes) {
758+
if (nbytes + PyBytesObject_SIZE <= nbytes) {
750759
PyErr_SetString(PyExc_OverflowError,
751760
"repeated bytes are too long");
752761
return NULL;
753762
}
754-
op = (PyBytesObject *)
755-
PyObject_MALLOC(sizeof(PyBytesObject) + nbytes);
763+
op = (PyBytesObject *)PyObject_MALLOC(PyBytesObject_SIZE + nbytes);
756764
if (op == NULL)
757765
return PyErr_NoMemory();
758766
PyObject_INIT_VAR(op, &PyBytes_Type, size);
@@ -2803,7 +2811,7 @@ static PyObject *
28032811
string_sizeof(PyBytesObject *v)
28042812
{
28052813
Py_ssize_t res;
2806-
res = sizeof(PyBytesObject) + Py_SIZE(v) * Py_TYPE(v)->tp_itemsize;
2814+
res = PyBytesObject_SIZE + Py_SIZE(v) * Py_TYPE(v)->tp_itemsize;
28072815
return PyLong_FromSsize_t(res);
28082816
}
28092817

@@ -3080,7 +3088,7 @@ static PyObject *str_iter(PyObject *seq);
30803088
PyTypeObject PyBytes_Type = {
30813089
PyVarObject_HEAD_INIT(&PyType_Type, 0)
30823090
"bytes",
3083-
sizeof(PyBytesObject),
3091+
PyBytesObject_SIZE,
30843092
sizeof(char),
30853093
string_dealloc, /* tp_dealloc */
30863094
0, /* tp_print */
@@ -3175,7 +3183,7 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize)
31753183
_Py_DEC_REFTOTAL;
31763184
_Py_ForgetReference(v);
31773185
*pv = (PyObject *)
3178-
PyObject_REALLOC((char *)v, sizeof(PyBytesObject) + newsize);
3186+
PyObject_REALLOC((char *)v, PyBytesObject_SIZE + newsize);
31793187
if (*pv == NULL) {
31803188
PyObject_Del(v);
31813189
PyErr_NoMemory();

0 commit comments

Comments
 (0)