@@ -61,6 +61,8 @@ module EnvMisc =
6161 let incrementalTypeCheckCacheSize = GetEnvInteger " mFSharp_IncrementalTypeCheckCacheSize" 5
6262
6363 let projectCacheSizeDefault = GetEnvInteger " mFSharp_ProjectCacheSizeDefault" 3
64+ let frameworkTcImportsCacheStrongSize = GetEnvInteger " mFSharp_frameworkTcImportsCacheStrongSizeDefault" 8
65+ let maxMBDefault = GetEnvInteger " mFSharp_maxMB" 2000
6466
6567//----------------------------------------------------------------------------
6668// Methods
@@ -2184,6 +2186,8 @@ type BackgroundCompiler(projectCacheSize, keepAssemblyContents, keepAllBackgroun
21842186 areSame= FSharpProjectOptions.AreSameForChecking,
21852187 areSameForSubsumption= FSharpProjectOptions.AreSubsumable)
21862188
2189+ let frameworkTcImportsCache = IncrementalFSharpBuild.FrameworkImportsCache( frameworkTcImportsCacheStrongSize)
2190+
21872191 /// CreateOneIncrementalBuilder (for background type checking). Note that fsc.fs also
21882192 /// creates an incremental builder used by the command line compiler.
21892193 let CreateOneIncrementalBuilder ( options : FSharpProjectOptions ) =
@@ -2200,7 +2204,7 @@ type BackgroundCompiler(projectCacheSize, keepAssemblyContents, keepAllBackgroun
22002204
22012205 let builderOpt , errorsAndWarnings =
22022206 IncrementalFSharpBuild.IncrementalBuilder.TryCreateBackgroundBuilderForProjectOptions
2203- ( scriptClosureCache.TryGet options, Array.toList options.ProjectFileNames,
2207+ ( frameworkTcImportsCache , scriptClosureCache.TryGet options, Array.toList options.ProjectFileNames,
22042208 Array.toList options.OtherOptions, projectReferences, options.ProjectDirectory,
22052209 options.UseScriptResolutionRules, options.IsIncompleteTypeCheckEnvironment, keepAssemblyContents, keepAllBackgroundResolutions)
22062210
@@ -2468,7 +2472,7 @@ type BackgroundCompiler(projectCacheSize, keepAssemblyContents, keepAllBackgroun
24682472 // including by SetAlternate.
24692473 let builderB , errorsB , decrementB = CreateOneIncrementalBuilder options
24702474 incrementalBuildersCache.Set( options, ( builderB, errorsB, decrementB))
2471- bc.StartBackgroundCompile( options)
2475+ // bc.StartBackgroundCompile(options)
24722476
24732477 member bc.NotifyProjectCleaned ( options : FSharpProjectOptions ) =
24742478 match incrementalBuildersCache.TryGetAny options with
@@ -2482,9 +2486,6 @@ type BackgroundCompiler(projectCacheSize, keepAssemblyContents, keepAllBackgroun
24822486 ()
24832487#endif
24842488
2485- member bc.InvalidateAll () =
2486- reactor.EnqueueOp ( fun () -> incrementalBuildersCache.Clear())
2487-
24882489 member bc.StartBackgroundCompile ( options ) =
24892490 reactor.StartBackgroundOp( fun () ->
24902491 let builderOpt , _ , _ = getOrCreateBuilder options
@@ -2506,6 +2507,18 @@ type BackgroundCompiler(projectCacheSize, keepAssemblyContents, keepAllBackgroun
25062507
25072508 member bc.CurrentQueueLength = reactor.CurrentQueueLength
25082509
2510+ member bc.ClearCaches () =
2511+ reactor.EnqueueOp ( fun () ->
2512+ incrementalBuildersCache.Clear()
2513+ frameworkTcImportsCache.Clear()
2514+ scriptClosureCache.Clear())
2515+
2516+ member bc.DownsizeCaches () =
2517+ reactor.EnqueueOp ( fun () ->
2518+ incrementalBuildersCache.Resize( keepStrongly= 1 , keepMax= 1 )
2519+ frameworkTcImportsCache.Downsize()
2520+ scriptClosureCache.Resize( keepStrongly= 1 , keepMax= 1 ))
2521+
25092522
25102523#if SILVERLIGHT
25112524#else
@@ -2937,6 +2950,11 @@ type FSharpChecker(projectCacheSize, keepAssemblyContents, keepAllBackgroundReso
29372950 areSame= AreSameForChecking3,
29382951 areSameForSubsumption= AreSubsumable3)
29392952
2953+ let mutable downsizedCaches = false
2954+ let mutable maxMB = maxMBDefault
2955+ let maxMemEvent = new Event< unit>()
2956+
2957+
29402958 static member Create () =
29412959 new FSharpChecker( projectCacheSizeDefault, false , true )
29422960
@@ -2959,6 +2977,7 @@ type FSharpChecker(projectCacheSize, keepAssemblyContents, keepAllBackgroundReso
29592977
29602978 member ic.ParseFileInProject ( filename , source , options ) =
29612979 async {
2980+ ic.CheckDownsizeCaches()
29622981 match parseFileInProjectCache.TryGet ( filename, source, options) with
29632982 | Some res -> return res
29642983 | None ->
@@ -2983,23 +3002,36 @@ type FSharpChecker(projectCacheSize, keepAssemblyContents, keepAllBackgroundReso
29833002 /// This function is called when the entire environment is known to have changed for reasons not encoded in the ProjectOptions of any project/compilation.
29843003 /// For example, the type provider approvals file may have changed.
29853004 member ic.InvalidateAll () =
2986- backgroundCompiler.InvalidateAll ()
3005+ ic.ClearCaches ()
29873006
3007+ member ic.ClearCaches () =
3008+ parseAndCheckFileInProjectCachePossiblyStale.Clear()
3009+ parseAndCheckFileInProjectCache.Clear()
3010+ braceMatchCache.Clear()
3011+ parseFileInProjectCache.Clear()
3012+ backgroundCompiler.ClearCaches()
3013+
3014+ member ic.CheckDownsizeCaches () =
3015+ if not downsizedCaches && System.GC.GetTotalMemory( false ) > int64 maxMB * 1024 L * 1024 L then
3016+ // If the maxMB limit is reached, drastic action is taken
3017+ // - reduce strong cache sizes to a minimum
3018+ downsizedCaches <- true
3019+ parseAndCheckFileInProjectCachePossiblyStale.Resize( keepStrongly= 1 )
3020+ parseAndCheckFileInProjectCache.Resize( keepStrongly= 1 )
3021+ braceMatchCache.Resize( keepStrongly= 1 )
3022+ parseFileInProjectCache.Resize( keepStrongly= 1 )
3023+ backgroundCompiler.DownsizeCaches()
3024+ maxMemEvent.Trigger( () )
3025+
29883026 /// This function is called when the entire environment is known to have changed for reasons not encoded in the ProjectOptions of any project/compilation.
29893027 /// For example, the type provider approvals file may have changed.
29903028 //
29913029 // This is for unit testing only
29923030 member ic.ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients () =
2993- ic.InvalidateAll()
2994- parseAndCheckFileInProjectCachePossiblyStale.Clear()
2995- parseAndCheckFileInProjectCache.Clear()
2996- braceMatchCache.Clear()
2997- parseFileInProjectCache.Clear()
2998- IncrementalFSharpBuild.ClearFrameworkTcImportsCache()
2999- for i in 0 .. 2 do
3000- System.GC.Collect()
3001- System.GC.WaitForPendingFinalizers()
3002- backgroundCompiler.WaitForBackgroundCompile() // flush AsyncOp
3031+ ic.ClearCaches()
3032+ System.GC.Collect()
3033+ System.GC.WaitForPendingFinalizers()
3034+ backgroundCompiler.WaitForBackgroundCompile() // flush AsyncOp
30033035
30043036 /// This function is called when the configuration is known to have changed for reasons not encoded in the ProjectOptions.
30053037 /// For example, dependent references may have been deleted or created.
@@ -3014,7 +3046,8 @@ type FSharpChecker(projectCacheSize, keepAssemblyContents, keepAllBackgroundReso
30143046 match checkAnswer with
30153047 | None
30163048 | Some FSharpCheckFileAnswer.Aborted ->
3017- backgroundCompiler.StartBackgroundCompile( options)
3049+ //backgroundCompiler.StartBackgroundCompile(options)
3050+ ()
30183051 | Some ( FSharpCheckFileAnswer.Succeeded typedResults) ->
30193052 foregroundTypeCheckCount <- foregroundTypeCheckCount + 1
30203053 parseAndCheckFileInProjectCachePossiblyStale.Set(( filename, options),( parseResults, typedResults, fileVersion))
@@ -3035,6 +3068,7 @@ type FSharpChecker(projectCacheSize, keepAssemblyContents, keepAllBackgroundReso
30353068 member ic.CheckFileInProject ( parseResults : FSharpParseFileResults , filename : string , fileVersion : int , source : string , options : FSharpProjectOptions , ? isResultObsolete , ? textSnapshotInfo : obj ) =
30363069 let ( IsResultObsolete ( isResultObsolete )) = defaultArg isResultObsolete ( IsResultObsolete( fun _ -> false ))
30373070 async {
3071+ ic.CheckDownsizeCaches()
30383072 let! checkAnswer = backgroundCompiler.CheckFileInProject( parseResults, filename, source, options, isResultObsolete, textSnapshotInfo)
30393073 ic.RecordTypeCheckFileInProjectResults( filename, options, parseResults, fileVersion, Some checkAnswer, source)
30403074 return checkAnswer
@@ -3046,13 +3080,15 @@ type FSharpChecker(projectCacheSize, keepAssemblyContents, keepAllBackgroundReso
30463080 let cachedResults = parseAndCheckFileInProjectCache.TryGet(( filename, source, options))
30473081 let ( IsResultObsolete ( isResultObsolete )) = defaultArg isResultObsolete ( IsResultObsolete( fun _ -> false ))
30483082 async {
3083+ ic.CheckDownsizeCaches()
30493084 let! parseResults , checkAnswer , usedCachedResults = backgroundCompiler.ParseAndCheckFileInProject( filename, source, options, isResultObsolete, textSnapshotInfo, cachedResults)
30503085 if not usedCachedResults then
30513086 ic.RecordTypeCheckFileInProjectResults( filename, options, parseResults, fileVersion, Some checkAnswer, source)
30523087 return ( parseResults, checkAnswer)
30533088 }
30543089
30553090 member ic.ParseAndCheckProject ( options ) =
3091+ ic.CheckDownsizeCaches()
30563092 backgroundCompiler.ParseAndCheckProject( options)
30573093
30583094 /// For a given script file, get the ProjectOptions implied by the #load closure
@@ -3141,6 +3177,9 @@ type FSharpChecker(projectCacheSize, keepAssemblyContents, keepAllBackgroundReso
31413177
31423178 member ic.FileTypeCheckStateIsDirty = backgroundCompiler.BeforeBackgroundFileCheck
31433179
3180+ member ic.MaxMemoryReached = maxMemEvent.Publish
3181+ member ic.MaxMemory with get() = maxMB and set v = maxMB <- v
3182+
31443183 static member Instance = globalInstance
31453184
31463185type FsiInteractiveChecker ( reactorOps : IReactorOperations , tcConfig , tcGlobals , tcImports , tcState , loadClosure ) =
0 commit comments