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