Skip to content

Commit a8e2a42

Browse files
committed
More options
1 parent 3ee7565 commit a8e2a42

1 file changed

Lines changed: 16 additions & 23 deletions

File tree

‎Objects/obmalloc.c‎

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,23 @@ _PyMem_RawFree(void *Py_UNUSED(ctx), void *ptr)
9393
static bool count_blocks(const mi_heap_t *, const mi_heap_area_t *,
9494
void *, size_t, void *);
9595

96-
// mimalloc v3 delays returning freed memory to the OS for much longer than v2
97-
// did (1000 ms purge delay and 4x arena multiplier, vs 10 ms and 10x), which
98-
// noticeably increases peak RSS. Restore the v2 timings, which have no
99-
// measurable speed cost. MIMALLOC_PURGE_DELAY and MIMALLOC_ARENA_PURGE_MULT
100-
// still take precedence.
96+
// mimalloc v3 keeps freed memory resident much longer than v2 did, which
97+
// noticeably increases peak RSS of short-running processes:
98+
// - All purges use purge_delay * arena_purge_mult (1000 ms * 4 by default),
99+
// while v2 purged freed pages after just purge_delay (10 ms).
100+
// - Delayed purges only release freed ranges of at least the minimal purge
101+
// size, which is 2 MiB when transparent huge pages are detected.
102+
// - Abandoned full pages hold memory that is not reused promptly.
103+
// Use v2-like timings, purge freed ranges at page granularity, and retain full
104+
// pages in their owning thread. None of these has a measurable speed cost.
105+
// The corresponding MIMALLOC_* environment variables still take precedence.
101106
static void
102107
set_mimalloc_defaults(void)
103108
{
104109
mi_option_set_default(mi_option_purge_delay, 10);
105-
mi_option_set_default(mi_option_arena_purge_mult, 10);
110+
mi_option_set_default(mi_option_arena_purge_mult, 1);
111+
mi_option_set_default(mi_option_arena_purge_min_size, 64); // KiB
112+
mi_option_set_default(mi_option_page_full_retain, -1);
106113
}
107114

108115
#ifdef Py_GIL_DISABLED
@@ -194,22 +201,9 @@ _PyMem_InitMimalloc(PyInterpreterState *interp)
194201
{
195202
set_mimalloc_defaults();
196203

197-
#ifdef Py_GIL_DISABLED
198-
assert(page->qsbr_node.next == NULL);
199-
if (page->qsbr_goal != 0) {
200-
if (mi_page_all_free(page)) {
201-
assert(page->qsbr_node.next == NULL);
202-
_PyThreadStateImpl *tstate = tstate_from_heap(mi_page_heap(page));
203-
// gh-159462: the owning tstate may differ from the current
204-
// one, but the heap is always owned by the current OS thread,
205-
// so the page list is not shared with other OS threads.
206-
assert(mi_page_heap(page)->thread_id == _Py_ThreadId());
207-
page->retire_expire = 0;
208-
llist_insert_tail(&tstate->mimalloc.page_list, &page->qsbr_node);
209-
}
210-
else {
211-
page->qsbr_goal = 0;
212-
}
204+
size_t base_offset = offsetof(PyObject, ob_type);
205+
if (_PyMem_DebugEnabled()) {
206+
base_offset += 2 * sizeof(size_t);
213207
}
214208
size_t debug_offsets[_Py_MIMALLOC_HEAP_COUNT] = {
215209
[_Py_MIMALLOC_HEAP_OBJECT] = base_offset,
@@ -231,7 +225,6 @@ _PyMem_InitMimalloc(PyInterpreterState *interp)
231225
}
232226
mimalloc_init_qsbr = NULL;
233227
return 0;
234-
#endif
235228
}
236229

237230
void

0 commit comments

Comments
 (0)