Issue #4445: save 3 bytes of memory (on average) per bytes allocation.

(This is a forward port of r67601).
This commit is contained in:
Mark Dickinson 2008-12-06 15:33:31 +00:00
parent 17fe364b44
commit fd24b323f9
2 changed files with 23 additions and 10 deletions

View File

@ -12,6 +12,11 @@ What's New in Python 3.1 alpha 0
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #4445: Replace "sizeof(PyBytesObject)" with
"offsetof(PyBytesObject, ob_sval) + 1" when allocating memory for
bytes instances. On a typical machine this saves 3 bytes of memory
(on average) per allocation of a bytes instance.
- Issue #4533: File read operation was dreadfully slow due to a slowly - Issue #4533: File read operation was dreadfully slow due to a slowly
growing read buffer. Fixed by using the same growth rate algorithm as growing read buffer. Fixed by using the same growth rate algorithm as
Python 2.x. Python 2.x.

View File

@ -5,6 +5,7 @@
#include "Python.h" #include "Python.h"
#include "bytes_methods.h" #include "bytes_methods.h"
#include <stddef.h>
static Py_ssize_t static Py_ssize_t
_getbuffer(PyObject *obj, Py_buffer *view) _getbuffer(PyObject *obj, Py_buffer *view)
@ -31,6 +32,14 @@ int null_strings, one_strings;
static PyBytesObject *characters[UCHAR_MAX + 1]; static PyBytesObject *characters[UCHAR_MAX + 1];
static PyBytesObject *nullstring; static PyBytesObject *nullstring;
/* PyBytesObject_SIZE gives the basic size of a string; any memory allocation
for a string of length n should request PyBytesObject_SIZE + n bytes.
Using PyBytesObject_SIZE instead of sizeof(PyBytesObject) saves
3 bytes per string allocation on a typical system.
*/
#define PyBytesObject_SIZE (offsetof(PyBytesObject, ob_sval) + 1)
/* /*
For both PyBytes_FromString() and PyBytes_FromStringAndSize(), the For both PyBytes_FromString() and PyBytes_FromStringAndSize(), the
parameter `size' denotes number of characters to allocate, not counting any parameter `size' denotes number of characters to allocate, not counting any
@ -83,14 +92,14 @@ PyBytes_FromStringAndSize(const char *str, Py_ssize_t size)
return (PyObject *)op; return (PyObject *)op;
} }
if (size > PY_SSIZE_T_MAX - sizeof(PyBytesObject)) { if (size > PY_SSIZE_T_MAX - PyBytesObject_SIZE) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"byte string is too large"); "byte string is too large");
return NULL; return NULL;
} }
/* Inline PyObject_NewVar */ /* Inline PyObject_NewVar */
op = (PyBytesObject *)PyObject_MALLOC(sizeof(PyBytesObject) + size); op = (PyBytesObject *)PyObject_MALLOC(PyBytesObject_SIZE + size);
if (op == NULL) if (op == NULL)
return PyErr_NoMemory(); return PyErr_NoMemory();
PyObject_INIT_VAR(op, &PyBytes_Type, size); PyObject_INIT_VAR(op, &PyBytes_Type, size);
@ -117,7 +126,7 @@ PyBytes_FromString(const char *str)
assert(str != NULL); assert(str != NULL);
size = strlen(str); size = strlen(str);
if (size > PY_SSIZE_T_MAX - sizeof(PyBytesObject)) { if (size > PY_SSIZE_T_MAX - PyBytesObject_SIZE) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"byte string is too long"); "byte string is too long");
return NULL; return NULL;
@ -138,7 +147,7 @@ PyBytes_FromString(const char *str)
} }
/* Inline PyObject_NewVar */ /* Inline PyObject_NewVar */
op = (PyBytesObject *)PyObject_MALLOC(sizeof(PyBytesObject) + size); op = (PyBytesObject *)PyObject_MALLOC(PyBytesObject_SIZE + size);
if (op == NULL) if (op == NULL)
return PyErr_NoMemory(); return PyErr_NoMemory();
PyObject_INIT_VAR(op, &PyBytes_Type, size); PyObject_INIT_VAR(op, &PyBytes_Type, size);
@ -746,13 +755,12 @@ string_repeat(register PyBytesObject *a, register Py_ssize_t n)
return (PyObject *)a; return (PyObject *)a;
} }
nbytes = (size_t)size; nbytes = (size_t)size;
if (nbytes + sizeof(PyBytesObject) <= nbytes) { if (nbytes + PyBytesObject_SIZE <= nbytes) {
PyErr_SetString(PyExc_OverflowError, PyErr_SetString(PyExc_OverflowError,
"repeated bytes are too long"); "repeated bytes are too long");
return NULL; return NULL;
} }
op = (PyBytesObject *) op = (PyBytesObject *)PyObject_MALLOC(PyBytesObject_SIZE + nbytes);
PyObject_MALLOC(sizeof(PyBytesObject) + nbytes);
if (op == NULL) if (op == NULL)
return PyErr_NoMemory(); return PyErr_NoMemory();
PyObject_INIT_VAR(op, &PyBytes_Type, size); PyObject_INIT_VAR(op, &PyBytes_Type, size);
@ -2803,7 +2811,7 @@ static PyObject *
string_sizeof(PyBytesObject *v) string_sizeof(PyBytesObject *v)
{ {
Py_ssize_t res; Py_ssize_t res;
res = sizeof(PyBytesObject) + Py_SIZE(v) * Py_TYPE(v)->tp_itemsize; res = PyBytesObject_SIZE + Py_SIZE(v) * Py_TYPE(v)->tp_itemsize;
return PyLong_FromSsize_t(res); return PyLong_FromSsize_t(res);
} }
@ -3080,7 +3088,7 @@ static PyObject *str_iter(PyObject *seq);
PyTypeObject PyBytes_Type = { PyTypeObject PyBytes_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT(&PyType_Type, 0)
"bytes", "bytes",
sizeof(PyBytesObject), PyBytesObject_SIZE,
sizeof(char), sizeof(char),
string_dealloc, /* tp_dealloc */ string_dealloc, /* tp_dealloc */
0, /* tp_print */ 0, /* tp_print */
@ -3175,7 +3183,7 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize)
_Py_DEC_REFTOTAL; _Py_DEC_REFTOTAL;
_Py_ForgetReference(v); _Py_ForgetReference(v);
*pv = (PyObject *) *pv = (PyObject *)
PyObject_REALLOC((char *)v, sizeof(PyBytesObject) + newsize); PyObject_REALLOC((char *)v, PyBytesObject_SIZE + newsize);
if (*pv == NULL) { if (*pv == NULL) {
PyObject_Del(v); PyObject_Del(v);
PyErr_NoMemory(); PyErr_NoMemory();