Description
Calling Silicon::verify
multiple times (sequentially) on the same verifier instance leaks memory, which is freed only when the verifier is destructed. In other words, there is some state that is not cleaned by Silicon's private reset
method. In Prusti, this causes our prusti-server
to go OOM after a while when verifying large programs, because we try to reuse the same verifier instance for multiple verification requests.
The memory leak can be debugged in VisualVM by inspecting the diff between heap dumps taken at different times after a manual GC run. To give an example, here is one of the paths from the verifier to one of the leaked viper.silicon.state.terms.Less
instances:
this - value: viper.silicon.state.terms.Less #1
<- head - class: scala.collection.immutable.$colon$colon, value: viper.silicon.state.terms.Less #1
<- equalityDefiningMembers - class: viper.silicon.state.terms.And, value: scala.collection.immutable.$colon$colon #3843
<- body - class: viper.silicon.state.terms.Let, value: viper.silicon.state.terms.And #1
<- body - class: viper.silicon.state.terms.Quantification, value: viper.silicon.state.terms.Let #1
<- [0] - class: java.lang.Object[], value: viper.silicon.state.terms.Quantification #1
<- prefix1 - class: scala.collection.immutable.Vector1, value: java.lang.Object[] #6000
<- postConditionAxioms - class: viper.silicon.supporters.functions.DefaultFunctionVerificationUnitProvider$functionsSupporter$, value: scala.collection.immutable.Vector1 #16
<- functionsSupporter$module - class: viper.silicon.verifier.DefaultMasterVerifier, value: viper.silicon.supporters.functions.DefaultFunctionVerificationUnitProvider$functionsSupporter$ #1
<- verifier (JNI local) - class: viper.silicon.Silicon, value: viper.silicon.verifier.DefaultMasterVerifier #1
For this particular instance, it seems that postConditionAxioms
in functionsSupporter
keeps growing.
Another example, for a viper.silicon.state.terms.Trigger
instance:
this - value: viper.silicon.state.terms.Trigger #5
<- head - class: scala.collection.immutable.$colon$colon, value: viper.silicon.state.terms.Trigger #5
<- triggers - class: viper.silicon.state.terms.Quantification, value: scala.collection.immutable.$colon$colon #4167
<- [1] - class: java.lang.Object[], value: viper.silicon.state.terms.Quantification #5
<- prefix1 - class: scala.collection.immutable.Vector1, value: java.lang.Object[] #5985
<- emittedFunctionAxioms - class: viper.silicon.supporters.functions.DefaultFunctionVerificationUnitProvider$functionsSupporter$, value: scala.collection.immutable.Vector1 #8
<- head - class: scala.collection.immutable.$colon$colon, value: viper.silicon.supporters.functions.DefaultFunctionVerificationUnitProvider$functionsSupporter$ #1
<- next - class: scala.collection.immutable.$colon$colon, value: scala.collection.immutable.$colon$colon #254
<- next - class: scala.collection.immutable.$colon$colon, value: scala.collection.immutable.$colon$colon #253
<- next - class: scala.collection.immutable.$colon$colon, value: scala.collection.immutable.$colon$colon #252
<- next - class: scala.collection.immutable.$colon$colon, value: scala.collection.immutable.$colon$colon #251
<- next - class: scala.collection.immutable.$colon$colon, value: scala.collection.immutable.$colon$colon #250
<- next - class: scala.collection.immutable.$colon$colon, value: scala.collection.immutable.$colon$colon #249
<- next - class: scala.collection.immutable.$colon$colon, value: scala.collection.immutable.$colon$colon #248
<- symbolDeclarationOrder - class: viper.silicon.verifier.DefaultMasterVerifier, value: scala.collection.immutable.$colon$colon #247
<- verifier (JNI local) - class: viper.silicon.Silicon, value: viper.silicon.verifier.DefaultMasterVerifier #1
I probably can find many more cases, if I keep looking at the heap dumps.