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.
Calling
Silicon::verifymultiple 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 privateresetmethod. In Prusti, this causes ourprusti-serverto 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.Lessinstances:For this particular instance, it seems that
postConditionAxiomsinfunctionsSupporterkeeps growing.Another example, for a
viper.silicon.state.terms.Triggerinstance:I probably can find many more cases, if I keep looking at the heap dumps.