From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2206) id 058963858C2D; Thu, 6 Jul 2023 15:38:41 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 058963858C2D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1688657921; bh=9lfFr+LsNa2Zxp85lKRFi4wk3WFuoiIGba1fnogXn3o=; h=From:To:Subject:Date:From; b=Q3jbhhNfgpoV4OYCmFQtb5luEe/EtZJVPw+RpxY4o/6vSgh1/tUZK83yX5KM/jNPc ojAHL8I3uc8ZzPlpSrJwEVHOjhko2yEUs7iJjJM4LBcx1o7aok4lwo9rzCWHS3jmKm OJcUuHvzsJ18XlUihSdJgI6DFlK3wP/AcJ1wSSpw= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Siddhesh Poyarekar To: glibc-cvs@sourceware.org Subject: [glibc] realloc: Limit chunk reuse to only growing requests [BZ #30579] X-Act-Checkin: glibc X-Git-Author: Siddhesh Poyarekar X-Git-Refname: refs/heads/master X-Git-Oldrev: 320ac7eeb47671e03ee26d4419b640fac0312390 X-Git-Newrev: 2fb12bbd092b0c10f1f2083216e723d2406e21c4 Message-Id: <20230706153841.058963858C2D@sourceware.org> Date: Thu, 6 Jul 2023 15:38:41 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=2fb12bbd092b0c10f1f2083216e723d2406e21c4 commit 2fb12bbd092b0c10f1f2083216e723d2406e21c4 Author: Siddhesh Poyarekar Date: Thu Jul 6 11:09:44 2023 -0400 realloc: Limit chunk reuse to only growing requests [BZ #30579] The trim_threshold is too aggressive a heuristic to decide if chunk reuse is OK for reallocated memory; for repeated small, shrinking allocations it leads to internal fragmentation and for repeated larger allocations that fragmentation may blow up even worse due to the dynamic nature of the threshold. Limit reuse only when it is within the alignment padding, which is 2 * size_t for heap allocations and a page size for mmapped allocations. There's the added wrinkle of THP, but this fix ignores it for now, pessimizing that case in favor of keeping fragmentation low. This resolves BZ #30579. Signed-off-by: Siddhesh Poyarekar Reported-by: Nicolas Dusart Reported-by: Aurelien Jarno Reviewed-by: Aurelien Jarno Tested-by: Aurelien Jarno Diff: --- malloc/malloc.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/malloc/malloc.c b/malloc/malloc.c index b8c0f4f580..e2f1a615a4 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -3417,16 +3417,23 @@ __libc_realloc (void *oldmem, size_t bytes) if (__glibc_unlikely (mtag_enabled)) *(volatile char*) oldmem; - /* Return the chunk as is whenever possible, i.e. there's enough usable space - but not so much that we end up fragmenting the block. We use the trim - threshold as the heuristic to decide the latter. */ - size_t usable = musable (oldmem); - if (bytes <= usable - && (unsigned long) (usable - bytes) <= mp_.trim_threshold) - return oldmem; - /* chunk corresponding to oldmem */ const mchunkptr oldp = mem2chunk (oldmem); + + /* Return the chunk as is if the request grows within usable bytes, typically + into the alignment padding. We want to avoid reusing the block for + shrinkages because it ends up unnecessarily fragmenting the address space. + This is also why the heuristic misses alignment padding for THP for + now. */ + size_t usable = musable (oldmem); + if (bytes <= usable) + { + size_t difference = usable - bytes; + if ((unsigned long) difference < 2 * sizeof (INTERNAL_SIZE_T) + || (chunk_is_mmapped (oldp) && difference <= GLRO (dl_pagesize))) + return oldmem; + } + /* its size */ const INTERNAL_SIZE_T oldsize = chunksize (oldp);