diff --git a/src/future/base_cache.rs b/src/future/base_cache.rs index 41e94aac..fc733003 100644 --- a/src/future/base_cache.rs +++ b/src/future/base_cache.rs @@ -1050,6 +1050,21 @@ pub(crate) struct Inner { clocks: Clocks, } +impl Drop for Inner { + fn drop(&mut self) { + // Ensure crossbeam-epoch to collect garbages (`deferred_fn`s) in the + // global bag so that previously cached values will be dropped. + for _ in 0..128 { + crossbeam_epoch::pin().flush(); + } + + // NOTE: The `CacheStore` (`cht`) will be dropped after returning from this + // `drop` method. It uses crossbeam-epoch internally, but we do not have to + // call `flush` for it because its `drop` methods do not create + // `deferred_fn`s, and drop its values in place. + } +} + // // functions/methods used by BaseCache // diff --git a/src/future/cache.rs b/src/future/cache.rs index 84d1c615..523f49cd 100644 --- a/src/future/cache.rs +++ b/src/future/cache.rs @@ -5454,6 +5454,18 @@ mod tests { assert_eq!(counters.value_dropped(), KEYS, "value_dropped"); } + // https://github.com/moka-rs/moka/issues/383 + #[tokio::test] + async fn ensure_gc_runs_when_dropping_cache() { + let cache = Cache::builder().build(); + let val = Arc::new(0); + cache + .get_with(1, std::future::ready(Arc::clone(&val))) + .await; + drop(cache); + assert_eq!(Arc::strong_count(&val), 1); + } + #[tokio::test] async fn test_debug_format() { let cache = Cache::new(10); diff --git a/src/sync/cache.rs b/src/sync/cache.rs index 4a154bdb..50b3f116 100644 --- a/src/sync/cache.rs +++ b/src/sync/cache.rs @@ -4831,6 +4831,19 @@ mod tests { assert_eq!(counters.value_dropped(), KEYS, "value_dropped"); } + // https://github.com/moka-rs/moka/issues/383 + #[test] + fn ensure_gc_runs_when_dropping_cache() { + let cache = Cache::builder().build(); + let val = Arc::new(0); + { + let val = Arc::clone(&val); + cache.get_with(1, move || val); + } + drop(cache); + assert_eq!(Arc::strong_count(&val), 1); + } + #[test] fn test_debug_format() { let cache = Cache::new(10); diff --git a/src/sync_base/base_cache.rs b/src/sync_base/base_cache.rs index 0d4571e1..304083dc 100644 --- a/src/sync_base/base_cache.rs +++ b/src/sync_base/base_cache.rs @@ -910,6 +910,21 @@ pub(crate) struct Inner { clocks: Clocks, } +impl Drop for Inner { + fn drop(&mut self) { + // Ensure crossbeam-epoch to collect garbages (`deferred_fn`s) in the + // global bag so that previously cached values will be dropped. + for _ in 0..128 { + crossbeam_epoch::pin().flush(); + } + + // NOTE: The `CacheStore` (`cht`) will be dropped after returning from this + // `drop` method. It uses crossbeam-epoch internally, but we do not have to + // call `flush` for it because its `drop` methods do not create + // `deferred_fn`s, and drop its values in place. + } +} + // // functions/methods used by BaseCache //