Skip to content

Commit f2a1867

Browse files
authored
bpo-30040: new empty dict uses key-sharing dict (GH-1080)
Sizeof new empty dict becomes 72 bytes from 240 bytes (amd64). It is same size to empty dict created by dict.clear().
1 parent fc06a19 commit f2a1867

File tree

4 files changed

+13
-8
lines changed

4 files changed

+13
-8
lines changed

Lib/test/test_descr.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5346,16 +5346,16 @@ class B(A):
53465346

53475347
a, b = A(), B()
53485348
self.assertEqual(sys.getsizeof(vars(a)), sys.getsizeof(vars(b)))
5349-
self.assertLess(sys.getsizeof(vars(a)), sys.getsizeof({}))
5349+
self.assertLess(sys.getsizeof(vars(a)), sys.getsizeof({"a":1}))
53505350
# Initial hash table can contain at most 5 elements.
53515351
# Set 6 attributes to cause internal resizing.
53525352
a.x, a.y, a.z, a.w, a.v, a.u = range(6)
53535353
self.assertNotEqual(sys.getsizeof(vars(a)), sys.getsizeof(vars(b)))
53545354
a2 = A()
53555355
self.assertEqual(sys.getsizeof(vars(a)), sys.getsizeof(vars(a2)))
5356-
self.assertLess(sys.getsizeof(vars(a)), sys.getsizeof({}))
5356+
self.assertLess(sys.getsizeof(vars(a)), sys.getsizeof({"a":1}))
53575357
b.u, b.v, b.w, b.t, b.s, b.r = range(6)
5358-
self.assertLess(sys.getsizeof(vars(b)), sys.getsizeof({}))
5358+
self.assertLess(sys.getsizeof(vars(b)), sys.getsizeof({"a":1}))
53595359

53605360

53615361
class DebugHelperMeta(type):

Lib/test/test_sys.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -982,8 +982,10 @@ def inner():
982982
check(int.__add__, size('3P2P'))
983983
# method-wrapper (descriptor object)
984984
check({}.__iter__, size('2P'))
985+
# empty dict
986+
check({}, size('nQ2P'))
985987
# dict
986-
check({}, size('nQ2P') + calcsize('2nP2n') + 8 + (8*2//3)*calcsize('n2P'))
988+
check({"a": 1}, size('nQ2P') + calcsize('2nP2n') + 8 + (8*2//3)*calcsize('n2P'))
987989
longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8}
988990
check(longdict, size('nQ2P') + calcsize('2nP2n') + 16 + (16*2//3)*calcsize('n2P'))
989991
# dictionary-keyview
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
New empty dict uses fewer memory for now. It used more memory than empty
2+
dict created by ``dict.clear()``. Patch by Inada Naoki.

Objects/dictobject.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -691,10 +691,8 @@ clone_combined_dict(PyDictObject *orig)
691691
PyObject *
692692
PyDict_New(void)
693693
{
694-
PyDictKeysObject *keys = new_keys_object(PyDict_MINSIZE);
695-
if (keys == NULL)
696-
return NULL;
697-
return new_dict(keys, NULL);
694+
dictkeys_incref(Py_EMPTY_KEYS);
695+
return new_dict(Py_EMPTY_KEYS, empty_values);
698696
}
699697

700698
/* Search index of hash table from offset of entry table */
@@ -1276,6 +1274,9 @@ _PyDict_NewPresized(Py_ssize_t minused)
12761274
Py_ssize_t newsize;
12771275
PyDictKeysObject *new_keys;
12781276

1277+
if (minused == 0) {
1278+
return PyDict_New();
1279+
}
12791280
/* There are no strict guarantee that returned dict can contain minused
12801281
* items without resize. So we create medium size dict instead of very
12811282
* large dict or MemoryError.

0 commit comments

Comments
 (0)