The "open" construct has a non-negligeable cost, as it applies a substitution to a signature before including it in the environment. With new syntax sugar like M.(x) and "let open X in", opening several times the same signature has become easy. However, if the signature is big (for example, if it is a pack of many interfaces), memory can become a problem.

For example, with Core, "open Core.Std" costs 50 MB of memory, opening it 20 times is 1 GB.

The provided patch improves sharing of substituted signatures, making multiple opens not more expensive than one open.

For Env.reset_cache, it should be done, indeed, but it is not a problem if it is not done (since the comparison is done with physical equality and caches of persistent signatures are cleared, there is no risk to use a signature from an older compilation).

For the mutable parts, I think they either relate to lazy evaluation, or they are only mutated when the signature is being built, and a signature is not mutated afterwards. So there should be no problem with sharing these mutable components.

Each open still involves adding all toplevel elements of the opened structure to the environment, which is not a no-op. I've create a source file with 10000 lines equal to "open Hashtbl". The maximum resident set size for compiling this module with ocamlc is reduced by a factor about 4 with the patch (but not more!), and compilation time by a factor of 7. This is good, but I would not go as far as to say that multiple opens become not more expensive than one open.

It would be possible to save some more space (a lot in your example) by removing redundant entries from the environment, i.e. [store_value env x y] would check first if [x] is not already associated (physically) with [y] before adding it.

Actually, it would even be possible to use such checks to display warnings when opening a module hides a value that was already bound in the environement.