You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Object allocation overallocates by 8 bytes for instances of tuple subclasses #100659
/* note that we need to add one, for the sentinel */
That +1 in nitems+1 has a couple of consequences for mytuple instances; the first of those is a possible perfomance opportunity, while the second is a minor bug.
on average (taking into account adjustments for alignment), we allocate 8 more bytes than necessary for each instance
sys.getsizeof consistently under-reports for these instances: the value reported is 8 bytes smaller than the value that was passed to PyObject_Malloc during object allocation
(Note: byte counts above assume a 64-bit platform.)
I did some hacky experimentation and was able to remove the +1 specifically for tuple subclasses with no apparent ill-effects. But the +1 definitely is needed for some varobjects (including PyHeapTypeObject, I think), and there may also be 3rd party extension code that either deliberately or inadvertently relies on it.
I haven't investigated whether there are other varobjects besides tuple subclasses for which the +1 could be removed.
Here's an ad-hoc reproducer (not exactly a proof of the overallocation, but at least strong evidence), on main. Let's start with a 3-element namedtuple called Point:
sys.getsizeof reports 64 bytes per Point instance, which sounds about right to me: 8 fields of 8 bytes each (2 for gc-tracking, 1 for the type pointer, 1 for the refcount, 1 for the tuple size, 3 for the three item pointers, no __dict__ (managed or otherwise), no __weakref__):
But if we create a large number of Point instances (with shared-integer items, so that we're not also allocating memory for the items), their ids never differ by less than 80:
Activity
mdickinson commentedon Jan 1, 2023
Here's an ad-hoc reproducer (not exactly a proof of the overallocation, but at least strong evidence), on main. Let's start with a 3-element namedtuple called
Point:sys.getsizeofreports 64 bytes perPointinstance, which sounds about right to me: 8 fields of 8 bytes each (2 for gc-tracking, 1 for the type pointer, 1 for the refcount, 1 for the tuple size, 3 for the three item pointers, no__dict__(managed or otherwise), no__weakref__):But if we create a large number of
Pointinstances (with shared-integer items, so that we're not also allocating memory for the items), their ids never differ by less than80:ionite34 commentedon Jan 2, 2023
Similar results here for main and 3.11.1, macos M1
Using
eval("(1, 2, 3)")to create a bunch of new tuples shows the expected 64 byte allocationSubclasses of
intanddictdo not appear to be affectedcorona10 commentedon Jan 10, 2023
#81381
This issue looks relevant, we might need to investigate which case could be reduced.
mdickinson commentedon Jan 10, 2023
@corona10 Thanks; that looks like the exact same issue. I'll close this as a duplicate.