Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

bpo-45340: Don't create object dictionaries unless actually needed#28802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
25 commits
Select commitHold shift + click to select a range
8214006
Add insertion order bit-vector to dict values to allow dicts to share…
markshannonSep 21, 2021
45c9814
Add NEWS
markshannonSep 23, 2021
c3de09e
Never change types' cached keys. It could invalidate inline attribute…
markshannonSep 23, 2021
58dd2a0
Lazily create object dictionaries. Work in progress.
markshannonSep 23, 2021
769183a
Restore specialization for inline attributes.
markshannonSep 30, 2021
1e6cd1f
Turn on stats
markshannonSep 30, 2021
a8fbb34
Fix specialization of LOAD/STORE_ATTR.
markshannonOct 1, 2021
37d8cc6
Turn off stats.
markshannonOct 1, 2021
0e022f9
Don't update shared keys version for deletion of value.
markshannonOct 4, 2021
ddd2e2c
Merge main into inline-attributes-with-opt
markshannonOct 6, 2021
e979575
Fix refrence leak.
markshannonOct 6, 2021
42361ad
Change 'InlineAttribute' to 'InstanceAttribute' as they are not inlin…
markshannonOct 6, 2021
e9b09d5
Merge branch 'main' into inline-attributes-with-opt
markshannonOct 6, 2021
70dc34f
Update gdb support to handle instance values.
markshannonOct 7, 2021
022f2c5
Rename SPLIT_KEYS opcodes to INSTANCE_VALUE.
markshannonOct 7, 2021
4ec5f11
Tidy test_gc
markshannonOct 7, 2021
1818a5a
Don't lose errors.
markshannonOct 7, 2021
bfc7be0
Make sure order is updated when deleting from values array.
markshannonOct 7, 2021
62a3a59
Update test_dict.
markshannonOct 7, 2021
7978220
Add NEWS
markshannonOct 8, 2021
b25b1d9
Merge branch 'main' into inline-attributes-with-opt
markshannonOct 12, 2021
7b2efa4
Merge branch 'main' into inline-attributes-with-opt
markshannonOct 12, 2021
459e29e
Make sure that instance dicts are GC tracked when necessary.
markshannonOct 12, 2021
83b90c5
Support older versions of Python in gdb.
markshannonOct 12, 2021
8c894f3
Rename function and move to internal header.
markshannonOct 12, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletionsInclude/cpython/object.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -270,6 +270,7 @@ struct _typeobject {

destructor tp_finalize;
vectorcallfunc tp_vectorcall;
Py_ssize_t tp_inline_values_offset;
};

/* The *real* layout of a type object when allocated on the heap */
Expand Down
2 changes: 2 additions & 0 deletionsInclude/internal/pycore_dict.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -101,6 +101,8 @@ extern uint64_t _pydict_global_version;

#define DICT_NEXT_VERSION() (++_pydict_global_version)

PyObject *_PyObject_MakeDictFromInstanceAttributes(PyObject *obj, PyDictValues *values);

#ifdef __cplusplus
}
#endif
Expand Down
10 changes: 10 additions & 0 deletionsInclude/internal/pycore_object.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -181,6 +181,16 @@ extern int _Py_CheckSlotResult(
extern PyObject* _PyType_AllocNoTrack(PyTypeObject *type, Py_ssize_t nitems);

extern int _PyObject_InitializeDict(PyObject *obj);
extern int _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
PyObject *name, PyObject *value);
PyObject * _PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,
PyObject *name);
PyDictValues ** _PyObject_ValuesPointer(PyObject *);
PyObject ** _PyObject_DictPointer(PyObject *);
int _PyObject_VisitInstanceAttributes(PyObject *self, visitproc visit, void *arg);
void _PyObject_ClearInstanceAttributes(PyObject *self);
void _PyObject_FreeInstanceAttributes(PyObject *self);
int _PyObject_IsInstanceDictEmpty(PyObject *);

#ifdef __cplusplus
}
Expand Down
1 change: 1 addition & 0 deletionsInclude/object.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -333,6 +333,7 @@ given type object has a specified feature.
*/

#ifndef Py_LIMITED_API

/* Set if instances of the type object are treated as sequences for pattern matching */
#define Py_TPFLAGS_SEQUENCE (1 << 5)
/* Set if instances of the type object are treated as mappings for pattern matching */
Expand Down
21 changes: 11 additions & 10 deletionsInclude/opcode.h
View file
Open in desktop

Some generated files are not rendered by default. Learn more abouthow customized files appear on GitHub.

5 changes: 3 additions & 2 deletionsLib/opcode.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -231,7 +231,7 @@ def jabs_op(name, op):
"BINARY_SUBSCR_DICT",
"JUMP_ABSOLUTE_QUICK",
"LOAD_ATTR_ADAPTIVE",
"LOAD_ATTR_SPLIT_KEYS",
"LOAD_ATTR_INSTANCE_VALUE",
"LOAD_ATTR_WITH_HINT",
"LOAD_ATTR_SLOT",
"LOAD_ATTR_MODULE",
Expand All@@ -242,8 +242,9 @@ def jabs_op(name, op):
"LOAD_METHOD_CACHED",
"LOAD_METHOD_CLASS",
"LOAD_METHOD_MODULE",
"LOAD_METHOD_NO_DICT",
"STORE_ATTR_ADAPTIVE",
"STORE_ATTR_SPLIT_KEYS",
"STORE_ATTR_INSTANCE_VALUE",
"STORE_ATTR_SLOT",
"STORE_ATTR_WITH_HINT",
# Super instructions
Expand Down
10 changes: 6 additions & 4 deletionsLib/test/test_descr.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5500,17 +5500,19 @@ class A:
class B(A):
pass

#Shrink keys by repeatedly creating instances
[(A(), B()) for _ in range(20)]

a, b = A(), B()
self.assertEqual(sys.getsizeof(vars(a)), sys.getsizeof(vars(b)))
self.assertLess(sys.getsizeof(vars(a)), sys.getsizeof({"a":1}))
# Initial hash table can containat most 5 elements.
# Initial hash table can containonly one or two elements.
# Set 6 attributes to cause internal resizing.
a.x, a.y, a.z, a.w, a.v, a.u = range(6)
self.assertNotEqual(sys.getsizeof(vars(a)), sys.getsizeof(vars(b)))
a2 = A()
self.assertEqual(sys.getsizeof(vars(a)), sys.getsizeof(vars(a2)))
self.assertLess(sys.getsizeof(vars(a)), sys.getsizeof({"a":1}))
b.u, b.v, b.w, b.t, b.s, b.r = range(6)
self.assertGreater(sys.getsizeof(vars(a)), sys.getsizeof(vars(a2)))
self.assertLess(sys.getsizeof(vars(a2)), sys.getsizeof({"a":1}))
self.assertLess(sys.getsizeof(vars(b)), sys.getsizeof({"a":1}))


Expand Down
5 changes: 2 additions & 3 deletionsLib/test/test_dict.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -994,8 +994,8 @@ class C:

@support.cpython_only
def test_splittable_setdefault(self):
"""split table mustbe combined when setdefault()
breaks insertion order"""
"""split table mustkeep correct insertion
order when attributes are adding using setdefault()"""
a, b = self.make_shared_key_dict(2)

a['a'] = 1
Expand All@@ -1005,7 +1005,6 @@ def test_splittable_setdefault(self):
size_b = sys.getsizeof(b)
b['a'] = 1

self.assertGreater(size_b, size_a)
self.assertEqual(list(a), ['x', 'y', 'z', 'a', 'b'])
self.assertEqual(list(b), ['x', 'y', 'z', 'b', 'a'])

Expand Down
29 changes: 14 additions & 15 deletionsLib/test/test_gc.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -444,7 +444,7 @@ def __getattr__(self, someattribute):
# 0, thus mutating the trash graph as a side effect of merely asking
# whether __del__ exists. This used to (before 2.3b1) crash Python.
# Now __getattr__ isn't called.
self.assertEqual(gc.collect(),4)
self.assertEqual(gc.collect(),2)
self.assertEqual(len(gc.garbage), garbagelen)

def test_boom2(self):
Expand All@@ -471,7 +471,7 @@ def __getattr__(self, someattribute):
# there isn't a second time, so this simply cleans up the trash cycle.
# We expect a, b, a.__dict__ and b.__dict__ (4 objects) to get
# reclaimed this way.
self.assertEqual(gc.collect(),4)
self.assertEqual(gc.collect(),2)
self.assertEqual(len(gc.garbage), garbagelen)

def test_boom_new(self):
Expand All@@ -491,7 +491,7 @@ def __getattr__(self, someattribute):
gc.collect()
garbagelen = len(gc.garbage)
del a, b
self.assertEqual(gc.collect(),4)
self.assertEqual(gc.collect(),2)
self.assertEqual(len(gc.garbage), garbagelen)

def test_boom2_new(self):
Expand All@@ -513,7 +513,7 @@ def __getattr__(self, someattribute):
gc.collect()
garbagelen = len(gc.garbage)
del a, b
self.assertEqual(gc.collect(),4)
self.assertEqual(gc.collect(),2)
self.assertEqual(len(gc.garbage), garbagelen)

def test_get_referents(self):
Expand DownExpand Up@@ -943,8 +943,8 @@ def getstats():
A()
t = gc.collect()
c, nc = getstats()
self.assertEqual(t,2*N) # instanceobject & its dict
self.assertEqual(c - oldc,2*N)
self.assertEqual(t, N) # instanceobjects
self.assertEqual(c - oldc, N)
self.assertEqual(nc - oldnc, 0)

# But Z() is not actually collected.
Expand All@@ -964,8 +964,8 @@ def getstats():
Z()
t = gc.collect()
c, nc = getstats()
self.assertEqual(t,2*N)
self.assertEqual(c - oldc,2*N)
self.assertEqual(t, N)
self.assertEqual(c - oldc, N)
self.assertEqual(nc - oldnc, 0)

# The A() trash should have been reclaimed already but the
Expand All@@ -974,8 +974,8 @@ def getstats():
zs.clear()
t = gc.collect()
c, nc = getstats()
self.assertEqual(t,4)
self.assertEqual(c - oldc,4)
self.assertEqual(t,2)
self.assertEqual(c - oldc,2)
self.assertEqual(nc - oldnc, 0)

gc.enable()
Expand DownExpand Up@@ -1128,8 +1128,7 @@ def test_collect_generation(self):
@cpython_only
def test_collect_garbage(self):
self.preclean()
# Each of these cause four objects to be garbage: Two
# Uncollectables and their instance dicts.
# Each of these cause two objects to be garbage:
Uncollectable()
Uncollectable()
C1055820(666)
Expand All@@ -1138,8 +1137,8 @@ def test_collect_garbage(self):
if v[1] != "stop":
continue
info = v[2]
self.assertEqual(info["collected"],2)
self.assertEqual(info["uncollectable"],8)
self.assertEqual(info["collected"],1)
self.assertEqual(info["uncollectable"],4)

# We should now have the Uncollectables in gc.garbage
self.assertEqual(len(gc.garbage), 4)
Expand All@@ -1156,7 +1155,7 @@ def test_collect_garbage(self):
continue
info = v[2]
self.assertEqual(info["collected"], 0)
self.assertEqual(info["uncollectable"],4)
self.assertEqual(info["uncollectable"],2)

# Uncollectables should be gone
self.assertEqual(len(gc.garbage), 0)
Expand Down
10 changes: 5 additions & 5 deletionsLib/test/test_sys.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1409,7 +1409,7 @@ def delx(self): del self.__x
check((1,2,3), vsize('') + 3*self.P)
# type
# static type: PyTypeObject
fmt = 'P2nPI13Pl4Pn9Pn11PIPP'
fmt = 'P2nPI13Pl4Pn9Pn12PIPP'
s = vsize(fmt)
check(int, s)
# class
Expand All@@ -1422,15 +1422,15 @@ def delx(self): del self.__x
'5P')
class newstyleclass(object): pass
# Separate block for PyDictKeysObject with 8 keys and 5 entries
check(newstyleclass, s + calcsize(DICT_KEY_STRUCT_FORMAT) +8 +5*calcsize("n2P"))
check(newstyleclass, s + calcsize(DICT_KEY_STRUCT_FORMAT) +32 +21*calcsize("n2P"))
# dict with shared keys
check(newstyleclass().__dict__, size('nQ2P') +5*self.P)
check(newstyleclass().__dict__, size('nQ2P') +15*self.P)
o = newstyleclass()
o.a = o.b = o.c = o.d = o.e = o.f = o.g = o.h = 1
# Separate block for PyDictKeysObject with 16 keys and 10 entries
check(newstyleclass, s + calcsize(DICT_KEY_STRUCT_FORMAT) +16 +10*calcsize("n2P"))
check(newstyleclass, s + calcsize(DICT_KEY_STRUCT_FORMAT) +32 +21*calcsize("n2P"))
# dict with shared keys
check(newstyleclass().__dict__, size('nQ2P') +10*self.P)
check(newstyleclass().__dict__, size('nQ2P') +13*self.P)
# unicode
# each tuple contains a string and its expected character size
# don't put any static strings here, as they may contain
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
Object attributes are held in an array instead of a dictionary. An object's
dictionary are created lazily, only when needed. Reduces the memory
consumption of a typical Python object by about 30%. Patch by Mark Shannon.
Loading

[8]ページ先頭

©2009-2025 Movatter.jp