diff --git a/src/kernel_services/abstract_interp/lmap.ml b/src/kernel_services/abstract_interp/lmap.ml
index b40ef8a586ef013d0fae248b9c98d1c099fb991a..0f5c56a0959d97126f77f8d1a270c038a755aa21 100644
--- a/src/kernel_services/abstract_interp/lmap.ml
+++ b/src/kernel_services/abstract_interp/lmap.ml
@@ -745,9 +745,7 @@ struct
 
   let iter = M.iter
 
-  let cached_fold ~f ~cache_name ~temporary ~joiner ~empty =
-    let cached_f = M.cached_fold ~f ~cache_name ~temporary ~joiner ~empty in
-    fun m -> cached_f m
+  let cached_fold = M.cached_fold
 
   let cached_map ~f ~cache ~temporary =
     let cached_f = M.cached_map ~f ~cache ~temporary in
diff --git a/src/kernel_services/abstract_interp/lmap_sig.ml b/src/kernel_services/abstract_interp/lmap_sig.ml
index fb35acef3172caa2a1de9706e24f09d9461daa93..8c39958e2a8f817b3bc577f4a9ac6b6806d6c605 100644
--- a/src/kernel_services/abstract_interp/lmap_sig.ml
+++ b/src/kernel_services/abstract_interp/lmap_sig.ml
@@ -187,8 +187,8 @@ module type S = sig
       modules, as they create persistent caches. *)
 
   val cached_fold :
+    cache:Hptmap_sig.cache_type ->
     f:(Base.t -> offsetmap -> 'a) ->
-    cache_name:string -> temporary:bool ->
     joiner:('a -> 'a -> 'a) -> empty:'a -> map -> 'a
 
   val cached_map :
diff --git a/src/kernel_services/abstract_interp/locations.ml b/src/kernel_services/abstract_interp/locations.ml
index ea8a60fe63e983d82ff09a51f8af5d723ba90d99..afc8590b20d27070a5f7842c12c4dc86fb642035 100644
--- a/src/kernel_services/abstract_interp/locations.ml
+++ b/src/kernel_services/abstract_interp/locations.ml
@@ -272,10 +272,10 @@ module Location_Bytes = struct
   let contains_addresses_of_any_locals =
     let f base _offsets = Base.is_any_formal_or_local base in
     let projection _base = Ival.top in
+    let cache = Hptmap_sig.PersistentCache "loc_top_any_locals" in
     let cached_f =
       cached_fold
-        ~cache_name:"loc_top_any_locals"
-        ~temporary:false
+        ~cache
         ~f
         ~projection
         ~joiner:(||)
diff --git a/src/kernel_services/abstract_interp/locations.mli b/src/kernel_services/abstract_interp/locations.mli
index 7e09abc3f7e61ad4c9abc41bba2fd28a9c7f6aed..081c430c0ed2cba6c6342f95ab7290889ba7abba 100644
--- a/src/kernel_services/abstract_interp/locations.mli
+++ b/src/kernel_services/abstract_interp/locations.mli
@@ -149,8 +149,7 @@ module Location_Bytes : sig
       @raise Error_Top in the cases [Top _]. *)
 
   val cached_fold:
-    cache_name:string ->
-    temporary:bool ->
+    cache:Hptmap_sig.cache_type ->
     f:(Base.t -> Ival.t -> 'a) ->
     projection:(Base.t -> Ival.t) ->
     joiner:('a -> 'a -> 'a) -> empty:'a -> t -> 'a
@@ -288,8 +287,7 @@ module Zone : sig
       @raise Error_Top in the case [Top Top]. *)
 
   val cached_fold :
-    cache_name:string ->
-    temporary:bool ->
+    cache:Hptmap_sig.cache_type ->
     f:(Base.t -> Int_Intervals.t -> 'b) ->
     projection:(Base.t -> Int_Intervals.t) ->
     joiner:('b -> 'b -> 'b) -> empty:'b -> t -> 'b
diff --git a/src/kernel_services/abstract_interp/map_lattice.ml b/src/kernel_services/abstract_interp/map_lattice.ml
index 483d860cf828de81c3cbcf4b7c860fbaac29e8df..713ad30918a9507f8649def90b1a3bd815e0d644 100644
--- a/src/kernel_services/abstract_interp/map_lattice.ml
+++ b/src/kernel_services/abstract_interp/map_lattice.ml
@@ -80,7 +80,7 @@ module type MapSet_Lattice = sig
   val fold_keys : (key -> 'a -> 'a) -> t -> 'a -> 'a
   val fold : (key -> v -> 'a -> 'a) -> t -> 'a -> 'a
   val cached_fold:
-    cache_name:string -> temporary:bool ->
+    cache:Hptmap_sig.cache_type ->
     f:(key -> v -> 'a) ->
     projection:(key -> v) -> joiner:('a -> 'a -> 'a) -> empty:'a -> t -> 'a
   val for_all: (key -> v -> bool) -> t -> bool
@@ -436,8 +436,8 @@ module Make_MapSet_Lattice
     | Top (s, _) -> KSet.fold (fun x acc -> f x Value.top acc) s acc
     | Map m      -> KVMap.fold f m acc
 
-  let cached_fold ~cache_name ~temporary ~f ~projection ~joiner ~empty =
-    let folded_f = KVMap.cached_fold ~cache_name ~temporary ~f ~joiner ~empty in
+  let cached_fold ~cache ~f ~projection ~joiner ~empty =
+    let folded_f = KVMap.cached_fold ~cache ~f ~joiner ~empty in
     function
     | Top (KSet.Top, _) -> raise Abstract_interp.Error_Top
     | Top (KSet.Set s, _) ->
diff --git a/src/kernel_services/abstract_interp/map_lattice.mli b/src/kernel_services/abstract_interp/map_lattice.mli
index 1825d8dadae768fcc181afa24fa881de46601b42..1ef2068c67b7212b05c03ee0b68f2efa4158c13f 100644
--- a/src/kernel_services/abstract_interp/map_lattice.mli
+++ b/src/kernel_services/abstract_interp/map_lattice.mli
@@ -125,7 +125,7 @@ module type MapSet_Lattice = sig
   val fold : (key -> v -> 'a -> 'a) -> t -> 'a -> 'a
 
   val cached_fold:
-    cache_name:string -> temporary:bool ->
+    cache:Hptmap_sig.cache_type ->
     f:(key -> v -> 'a) ->
     projection:(key -> v) -> joiner:('a -> 'a -> 'a) -> empty:'a -> t -> 'a
 
diff --git a/src/libraries/utils/binary_cache.mli b/src/libraries/utils/binary_cache.mli
index 26cbfbbe786abb6b5fcdf103043b15f0ed47f96e..bd06303220591ccf119761273821d8c10abe14da 100644
--- a/src/libraries/utils/binary_cache.mli
+++ b/src/libraries/utils/binary_cache.mli
@@ -24,12 +24,6 @@
     you understand what happens in this module, and do not forget that
     those caches are not aware of projects. *)
 
-val memory_footprint_var_name: string
-
-val cache_size: int
-(** Size of the caches. Controlled by environment variable
-    [memory_footprint_var_name]. *)
-
 module type Cacheable = sig
   type t
   val hash : t -> int
diff --git a/src/libraries/utils/hptmap.ml b/src/libraries/utils/hptmap.ml
index 7766433682c661555a31392920d1d112d28675f3..15a34cae3f11f18749e5ac1888fac60544bc10d7 100644
--- a/src/libraries/utils/hptmap.ml
+++ b/src/libraries/utils/hptmap.ml
@@ -339,42 +339,6 @@ module Shape(Key: Id_Datatype) = struct
   let register_clear_cache f = clear_caches_ref := f :: !clear_caches_ref
   let clear_caches () = List.iter (fun f -> f ()) !clear_caches_ref
 
-  let cached_fold ~cache_name ~temporary ~f ~joiner ~empty =
-    if debug_cache then Format.eprintf "CACHE cached_fold %s@." cache_name;
-    let cache_size = Binary_cache.cache_size in
-    let cache = Array.make cache_size (Empty, empty) in
-    let hash t = abs (hash t mod cache_size) in
-    let reset () = Array.fill cache 0 cache_size (Empty, empty) in
-    if not temporary then register_clear_cache reset;
-    fun m ->
-      let rec traverse t =
-        let mem result =
-          cache.(hash t) <- (t, result);
-          result
-        in
-        let find () =
-          let t', r = cache.(hash t) in
-          if equal t t' then r
-          else raise Not_found
-        in
-        match t with
-        | Empty -> empty
-        | Leaf(key, value, _) ->
-          (try
-             find ()
-           with Not_found ->
-             mem (f key value)
-          )
-        | Branch(_p, _m, s0, s1, _) ->
-          try
-            find ()
-          with Not_found ->
-            let result0 = traverse s0 in
-            let result1 = traverse s1 in
-            mem (joiner result0 result1)
-      in
-      traverse m
-
   module Cacheable (X: sig type v end) = struct
     type t = (key, X.v) tree
     let hash : t -> int = hash_generic
@@ -382,6 +346,26 @@ module Shape(Key: Id_Datatype) = struct
     let equal : t -> t -> bool = (==)
   end
 
+  let is_persistent_cache = function
+    | Hptmap_sig.PersistentCache _ -> true
+    | _ -> false
+
+  let make_unary_cache (type v result) empty name cache =
+    match cache with
+    | Hptmap_sig.NoCache -> (fun f x -> f x)
+    | Hptmap_sig.TemporaryCache cache_name
+    | Hptmap_sig.PersistentCache cache_name ->
+      if debug_cache
+      then Format.eprintf "Hptmap CACHE %s : %s@." name cache_name;
+      let module Arg = Cacheable (struct type nonrec v = v end) in
+      let module R = struct
+        type t = result
+        let sentinel : t = empty
+      end in
+      let module Cache = Binary_cache.Arity_One (Arg) (R) in
+      if is_persistent_cache cache then register_clear_cache Cache.clear;
+      Cache.merge
+
   type ('v1, 'v2, 'result) cache_type =
     | Any: ('v1, 'v2, 'result) cache_type
     | Predicate: ('v1, 'v2, bool) cache_type
@@ -417,10 +401,20 @@ module Shape(Key: Id_Datatype) = struct
           let module Cache = Binary_cache.Symmetric_Binary_Predicate (Arg1) in
           Cache.clear, Cache.merge
       in
-      if cache = Hptmap_sig.PersistentCache cache_name
-      then register_clear_cache clear_cache;
+      if is_persistent_cache cache then register_clear_cache clear_cache;
       merge_cache
 
+  let cached_fold ~cache ~f ~joiner ~empty =
+    let cache_merge = make_unary_cache empty "cached_fold" cache in
+    let rec compute t = cache_merge traverse t
+    and traverse t =
+      match t with
+      | Empty -> empty
+      | Leaf (key, value, _) -> f key value
+      | Branch (_p, _m, s0, s1, _) -> joiner (compute s0) (compute s1)
+    in
+    compute
+
   let fold2_join_heterogeneous ~cache ~empty_left ~empty_right ~both ~join ~empty =
     let cache_merge = make_binary_cache empty "fold2" cache in
     let rec compute s t = cache_merge aux s t
diff --git a/src/libraries/utils/hptmap_sig.ml b/src/libraries/utils/hptmap_sig.ml
index 1579855eb92d871a42a69ea461bd1e3ab23664e7..f53a23a5a27b233a91334da8d7bb1e4bb32854cc 100644
--- a/src/libraries/utils/hptmap_sig.ml
+++ b/src/libraries/utils/hptmap_sig.ml
@@ -118,8 +118,7 @@ module type Shape = sig
       the map's ordering. *)
 
   val cached_fold :
-    cache_name:string ->
-    temporary:bool ->
+    cache:cache_type ->
     f:(key -> 'v -> 'b) ->
     joiner:('b -> 'b -> 'b) ->
     empty:'b ->
diff --git a/src/plugins/eva/domains/equality/equality.ml b/src/plugins/eva/domains/equality/equality.ml
index b621bd895d4020ce4f85c454df80844b815caccb..5101d2f13c1dc39d5df6b43e5763e3c336d84b9c 100644
--- a/src/plugins/eva/domains/equality/equality.ml
+++ b/src/plugins/eva/domains/equality/equality.ml
@@ -400,12 +400,11 @@ module Set = struct
       fmt map
 
   let keys =
-    let cache_name = "Equality.Set.keys" in
-    let temporary = false in
+    let cache = Hptmap_sig.PersistentCache "Equality.Set.keys" in
     let f k _ = if HCE.is_lval k then Leaf k else Empty in
     let joiner t1 t2 = Node (t1, t2) in
     let empty = Empty in
-    cached_fold ~cache_name ~temporary ~f ~joiner ~empty
+    cached_fold ~cache ~f ~joiner ~empty
 
   let lvalues_only_left =
     let cache = Hptmap_sig.PersistentCache "Equality.Set.elements_only_left" in
diff --git a/src/plugins/from/functionwise.ml b/src/plugins/from/functionwise.ml
index 8907b731dbbc2ac05953d066fd67ec442d89eb87..de69304cdf86af51a3b79d44b076cb2868bafd6d 100644
--- a/src/plugins/from/functionwise.ml
+++ b/src/plugins/from/functionwise.ml
@@ -66,9 +66,9 @@ module To_Use = struct
       in
       let joiner = Zone.join in
       let projection _ = Int_Intervals.top in
+      let cache = Hptmap_sig.TemporaryCache "from cleanup" in
       let zone_substitution =
-        Zone.cached_fold ~cache_name:"from cleanup" ~temporary:true
-          ~f ~joiner ~empty:Zone.bottom ~projection
+        Zone.cached_fold ~cache ~f ~joiner ~empty:Zone.bottom ~projection
       in
       let zone_substitution x =
         try