mirror of https://github.com/python/cpython
Issue #4445: save 3 bytes (on average, on a typical machine) per
string allocation.
This commit is contained in:
parent
205e719fac
commit
826f3fefe5
|
@ -631,8 +631,8 @@ class SizeofTest(unittest.TestCase):
|
||||||
# slice
|
# slice
|
||||||
check(slice(1), size(h + '3P'))
|
check(slice(1), size(h + '3P'))
|
||||||
# str
|
# str
|
||||||
check('', size(vh + 'lic'))
|
check('', struct.calcsize(vh + 'li') + 1)
|
||||||
check('abc', size(vh + 'lic') + 3*self.c)
|
check('abc', struct.calcsize(vh + 'li') + 1 + 3*self.c)
|
||||||
# super
|
# super
|
||||||
check(super(int), size(h + '3P'))
|
check(super(int), size(h + '3P'))
|
||||||
# tuple
|
# tuple
|
||||||
|
|
|
@ -12,6 +12,11 @@ What's New in Python 2.7 alpha 1
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #4445: Replace "sizeof(PyStringObject)" with
|
||||||
|
"offsetof(PyStringObject, ob_sval) + 1" when allocating memory for
|
||||||
|
str instances. On a typical machine this saves 3 bytes of memory
|
||||||
|
(on average) per string allocation.
|
||||||
|
|
||||||
- Issue #3996: On Windows, the PyOS_CheckStack function would cause the
|
- Issue #3996: On Windows, the PyOS_CheckStack function would cause the
|
||||||
interpreter to abort ("Fatal Python error: Could not reset the stack!")
|
interpreter to abort ("Fatal Python error: Could not reset the stack!")
|
||||||
instead of throwing a MemoryError.
|
instead of throwing a MemoryError.
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "Python.h"
|
#include "Python.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#ifdef COUNT_ALLOCS
|
#ifdef COUNT_ALLOCS
|
||||||
int null_strings, one_strings;
|
int null_strings, one_strings;
|
||||||
|
@ -22,6 +23,14 @@ static PyStringObject *nullstring;
|
||||||
*/
|
*/
|
||||||
static PyObject *interned;
|
static PyObject *interned;
|
||||||
|
|
||||||
|
/* PyStringObject_SIZE gives the basic size of a string; any memory allocation
|
||||||
|
for a string of length n should request PyStringObject_SIZE + n bytes.
|
||||||
|
|
||||||
|
Using PyStringObject_SIZE instead of sizeof(PyStringObject) saves
|
||||||
|
3 bytes per string allocation on a typical system.
|
||||||
|
*/
|
||||||
|
#define PyStringObject_SIZE (offsetof(PyStringObject, ob_sval) + 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
For both PyString_FromString() and PyString_FromStringAndSize(), the
|
For both PyString_FromString() and PyString_FromStringAndSize(), the
|
||||||
parameter `size' denotes number of characters to allocate, not counting any
|
parameter `size' denotes number of characters to allocate, not counting any
|
||||||
|
@ -74,13 +83,13 @@ PyString_FromStringAndSize(const char *str, Py_ssize_t size)
|
||||||
return (PyObject *)op;
|
return (PyObject *)op;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size > PY_SSIZE_T_MAX - sizeof(PyStringObject)) {
|
if (size > PY_SSIZE_T_MAX - PyStringObject_SIZE) {
|
||||||
PyErr_SetString(PyExc_OverflowError, "string is too large");
|
PyErr_SetString(PyExc_OverflowError, "string is too large");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inline PyObject_NewVar */
|
/* Inline PyObject_NewVar */
|
||||||
op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size);
|
op = (PyStringObject *)PyObject_MALLOC(PyStringObject_SIZE + size);
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
PyObject_INIT_VAR(op, &PyString_Type, size);
|
PyObject_INIT_VAR(op, &PyString_Type, size);
|
||||||
|
@ -114,7 +123,7 @@ PyString_FromString(const char *str)
|
||||||
|
|
||||||
assert(str != NULL);
|
assert(str != NULL);
|
||||||
size = strlen(str);
|
size = strlen(str);
|
||||||
if (size > PY_SSIZE_T_MAX - sizeof(PyStringObject)) {
|
if (size > PY_SSIZE_T_MAX - PyStringObject_SIZE) {
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"string is too long for a Python string");
|
"string is too long for a Python string");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -135,7 +144,7 @@ PyString_FromString(const char *str)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inline PyObject_NewVar */
|
/* Inline PyObject_NewVar */
|
||||||
op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size);
|
op = (PyStringObject *)PyObject_MALLOC(PyStringObject_SIZE + size);
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
PyObject_INIT_VAR(op, &PyString_Type, size);
|
PyObject_INIT_VAR(op, &PyString_Type, size);
|
||||||
|
@ -992,14 +1001,14 @@ string_concat(register PyStringObject *a, register PyObject *bb)
|
||||||
"strings are too large to concat");
|
"strings are too large to concat");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inline PyObject_NewVar */
|
/* Inline PyObject_NewVar */
|
||||||
if (size > PY_SSIZE_T_MAX - sizeof(PyStringObject)) {
|
if (size > PY_SSIZE_T_MAX - PyStringObject_SIZE) {
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"strings are too large to concat");
|
"strings are too large to concat");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size);
|
op = (PyStringObject *)PyObject_MALLOC(PyStringObject_SIZE + size);
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
PyObject_INIT_VAR(op, &PyString_Type, size);
|
PyObject_INIT_VAR(op, &PyString_Type, size);
|
||||||
|
@ -1036,13 +1045,12 @@ string_repeat(register PyStringObject *a, register Py_ssize_t n)
|
||||||
return (PyObject *)a;
|
return (PyObject *)a;
|
||||||
}
|
}
|
||||||
nbytes = (size_t)size;
|
nbytes = (size_t)size;
|
||||||
if (nbytes + sizeof(PyStringObject) <= nbytes) {
|
if (nbytes + PyStringObject_SIZE <= nbytes) {
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"repeated string is too long");
|
"repeated string is too long");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
op = (PyStringObject *)
|
op = (PyStringObject *)PyObject_MALLOC(PyStringObject_SIZE + nbytes);
|
||||||
PyObject_MALLOC(sizeof(PyStringObject) + nbytes);
|
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
PyObject_INIT_VAR(op, &PyString_Type, size);
|
PyObject_INIT_VAR(op, &PyString_Type, size);
|
||||||
|
@ -3940,7 +3948,7 @@ static PyObject *
|
||||||
string_sizeof(PyStringObject *v)
|
string_sizeof(PyStringObject *v)
|
||||||
{
|
{
|
||||||
Py_ssize_t res;
|
Py_ssize_t res;
|
||||||
res = sizeof(PyStringObject) + v->ob_size * v->ob_type->tp_itemsize;
|
res = PyStringObject_SIZE + v->ob_size * v->ob_type->tp_itemsize;
|
||||||
return PyInt_FromSsize_t(res);
|
return PyInt_FromSsize_t(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4179,7 +4187,7 @@ If the argument is a string, the return value is the same object.");
|
||||||
PyTypeObject PyString_Type = {
|
PyTypeObject PyString_Type = {
|
||||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||||
"str",
|
"str",
|
||||||
sizeof(PyStringObject),
|
PyStringObject_SIZE,
|
||||||
sizeof(char),
|
sizeof(char),
|
||||||
string_dealloc, /* tp_dealloc */
|
string_dealloc, /* tp_dealloc */
|
||||||
(printfunc)string_print, /* tp_print */
|
(printfunc)string_print, /* tp_print */
|
||||||
|
@ -4275,7 +4283,7 @@ _PyString_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(PyStringObject) + newsize);
|
PyObject_REALLOC((char *)v, PyStringObject_SIZE + newsize);
|
||||||
if (*pv == NULL) {
|
if (*pv == NULL) {
|
||||||
PyObject_Del(v);
|
PyObject_Del(v);
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
|
|
Loading…
Reference in New Issue