-
Notifications
You must be signed in to change notification settings - Fork 123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memory leak related to type substitutions #888
Comments
Previously, unevaluated `apSubst` thunks were retaining copies of a very large `Subst` value. Fixes #888.
Adding strictness can fix the persistence of the |
It certainly seems like type substitution is the/a major bottleneck in the typechecker. Do we have specific algorithmic changes in mind that might help? |
The main problem is that to keep the substitution idempotent, every time you extend it you need to traverse the whole substitution to update all the old entries. This keeps getting slower and slower as the map grows. I've been thinking about strategies to "evict" some entries from the substitution map to keep it small, in particular when you leave the scope of some bound type variables. I haven't worked out the details yet. The trick is to implement a strategy like that and improve the asymptotic behavior without slowing down the common cases too much. |
It would be quite the refactoring, but would it work to instead represent unification variables using Alternately, we could drop the idempotent invariant and instead do path compression on lookups or something. That wouldn't help shrink the substitution, but it would keep us from having to traverse it constantly. |
That kind of refactoring might be worthwhile. Dropping the idempotency requirement would probably make it necessary to change all the unification code to monadic style; even without path compression, we would at least need a reader monad to do variable lookups. And if we're going to go that far, we might as well use |
This might be relevant: http://okmij.org/ftp/ML/generalization.html |
We also needed to rewrite `anyJust2` to make it more strict, to avoid reintroducing the space leak of issue #888.
We also needed to rewrite `anyJust2` to make it more strict, to avoid reintroducing the space leak of issue #888.
While doing some memory profiling of the cryptol interpreter recently with
+RTS -hb
, I discovered that loading cryptol modules produces a large amount ofvoid
data on the heap that remains in memory throughout evaluation, basically until the REPL exits.Profiling with
+RTS -hbvoid -hy
of+RTS -hbvoid -hc
shows that thevoid
data is mostly made ofIntMap
and(,)
values which are created by the@@
operation fromCryptol.TypeCheck.Subst
. Retainer analysis shows that there are calls toapSubst
that are hanging onto theseSubst
values that contain theIntMaps
of pairs.As I understand it, here's what is happening: During type inference, the "current substitution" for unification variables grows rather large (tens of megabytes for a moderate-sized module). When type inference is done, the "current substitution" is then applied to some of the result values with
apSubst
. However, the result values are not sufficiently forced, leaving some applications ofapSubst
unevaluated. This causes the program to retain the entire (large) substitution value.The text was updated successfully, but these errors were encountered: