@@ -433,13 +433,27 @@ int _mi_prim_commit(void* start, size_t size, bool* is_zero) {
433433 return err ;
434434}
435435
436+ int _mi_prim_reuse (void * start , size_t size ) {
437+ #if defined(__APPLE__ ) && defined(MADV_FREE_REUSE )
438+ return unix_madvise (start , size , MADV_FREE_REUSE );
439+ #endif
440+ return 0 ;
441+ }
442+
436443int _mi_prim_decommit (void * start , size_t size , bool * needs_recommit ) {
437444 int err = 0 ;
438- // decommit: use MADV_DONTNEED as it decreases rss immediately (unlike MADV_FREE)
439- err = unix_madvise (start , size , MADV_DONTNEED );
440445 #if !MI_DEBUG && MI_SECURE <=2
441446 * needs_recommit = false;
447+ #if defined(__APPLE__ ) && defined(MADV_FREE_REUSABLE )
448+ // decommit on macOS: use MADV_FREE_REUSABLE as it does immediate rss accounting (issue #1097)
449+ err = unix_madvise (start , size , MADV_FREE_REUSABLE );
450+ #else
451+ // decommit: use MADV_DONTNEED as it decreases rss immediately (unlike MADV_FREE)
452+ err = unix_madvise (start , size , MADV_DONTNEED );
453+ #endif
442454 #else
455+ // note: don't use MADV_FREE_REUSABLE as the range may contain protected areas
456+ err = unix_madvise (start , size , MADV_DONTNEED );
443457 * needs_recommit = true;
444458 mprotect (start , size , PROT_NONE );
445459 #endif
@@ -454,22 +468,29 @@ int _mi_prim_decommit(void* start, size_t size, bool* needs_recommit) {
454468}
455469
456470int _mi_prim_reset (void * start , size_t size ) {
457- // We try to use `MADV_FREE` as that is the fastest. A drawback though is that it
471+ int err = 0 ;
472+ #if defined(__APPLE__ ) && defined(MADV_FREE_REUSABLE )
473+ // on macOS we try to use MADV_FREE_REUSABLE as it seems the fastest
474+ err = unix_madvise (start , size , MADV_FREE_REUSABLE );
475+ if (err == 0 ) return 0 ;
476+ // fall through
477+ #endif
478+
479+ #if defined(MADV_FREE )
480+ // Otherwise, we try to use `MADV_FREE` as that is the fastest. A drawback though is that it
458481 // will not reduce the `rss` stats in tools like `top` even though the memory is available
459482 // to other processes. With the default `MIMALLOC_PURGE_DECOMMITS=1` we ensure that by
460483 // default `MADV_DONTNEED` is used though.
461- #if defined(MADV_FREE )
462484 static _Atomic (size_t ) advice = MI_ATOMIC_VAR_INIT (MADV_FREE );
463485 int oadvice = (int )mi_atomic_load_relaxed (& advice );
464- int err ;
465486 while ((err = unix_madvise (start , size , oadvice )) != 0 && errno == EAGAIN ) { errno = 0 ; };
466487 if (err != 0 && errno == EINVAL && oadvice == MADV_FREE ) {
467488 // if MADV_FREE is not supported, fall back to MADV_DONTNEED from now on
468489 mi_atomic_store_release (& advice , (size_t )MADV_DONTNEED );
469490 err = unix_madvise (start , size , MADV_DONTNEED );
470491 }
471492 #else
472- int err = unix_madvise (start , size , MADV_DONTNEED );
493+ err = unix_madvise (start , size , MADV_DONTNEED );
473494 #endif
474495 return err ;
475496}
0 commit comments