|
| 1 | +<!DOCTYPE html> |
| 2 | +<html lang="en"> |
| 3 | + <head> |
| 4 | + <meta charset="utf-8"> |
| 5 | + <title>Compiler Services: Notes on the FSharpChecker caches |
| 6 | +</title> |
| 7 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| 8 | + <meta name="description" content="F# compiler services for creating IDE tools, language extensions and for F# embedding"> |
| 9 | + <meta name="author" content="Microsoft Corporation, Dave Thomas, Anh-Dung Phan, Tomas Petricek"> |
| 10 | + |
| 11 | + <script src="https://code.jquery.com/jquery-1.8.0.js"></script> |
| 12 | + <script src="https://code.jquery.com/ui/1.8.23/jquery-ui.js"></script> |
| 13 | + <script src="https://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/js/bootstrap.min.js"></script> |
| 14 | + <link href="https://netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/css/bootstrap-combined.min.css" rel="stylesheet"> |
| 15 | + |
| 16 | + <link type="text/css" rel="stylesheet" href="./content/style.css" /> |
| 17 | + <link type="text/css" rel="stylesheet" href="./content/fcs.css" /> |
| 18 | + <script type="text/javascript" src="./content/tips.js"></script> |
| 19 | + <!-- HTML5 shim, for IE6-8 support of HTML5 elements --> |
| 20 | + <!--[if lt IE 9]> |
| 21 | + <script src="https://html5shim.googlecode.com/svn/trunk/html5.js"></script> |
| 22 | + <![endif]--> |
| 23 | + </head> |
| 24 | + <body> |
| 25 | + <div class="container"> |
| 26 | + <div class="masthead"> |
| 27 | + <ul class="nav nav-pills pull-right"> |
| 28 | + <li><a href="http://fsharp.org">fsharp.org</a></li> |
| 29 | + <li><a href="http://github.com/fsharp/FSharp.Compiler.Service">github page</a></li> |
| 30 | + </ul> |
| 31 | + <h3 class="muted">F# Compiler Services</h3> |
| 32 | + </div> |
| 33 | + <hr /> |
| 34 | + <div class="row"> |
| 35 | + <div class="span9" id="main"> |
| 36 | + |
| 37 | +<h1><a name="Compiler-Services-Notes-on-the-FSharpChecker-caches" class="anchor" href="#Compiler-Services-Notes-on-the-FSharpChecker-caches">Compiler Services: Notes on the FSharpChecker caches</a></h1> |
| 38 | +<p>This is a design note on the FSharpChecker component and its caches. See also the notes on the <a href="queue.html">FSharpChecker operations queue</a></p> |
| 39 | +<p>Each FSharpChecker object maintains a set of caches. These are</p> |
| 40 | +<ul> |
| 41 | +<li> |
| 42 | +<p><code>scriptClosureCache</code> - an MRU cache of default size <code>projectCacheSize</code> that caches the |
| 43 | +computation of GetProjectOptionsFromScript. This computation can be lengthy as it can involve processing the transative closure |
| 44 | +of all <code>#load</code> directives, which in turn can mean parsing an unbounded number of script files</p> |
| 45 | +</li> |
| 46 | +<li> |
| 47 | +<p><code>incrementalBuildersCache</code> - an MRU cache of projects where a handle is being kept to their incremental checking state, |
| 48 | +of default size <code>projectCacheSize</code> (= 3 unless explicitly set as a parameter). |
| 49 | +The "current background project" (see the <a href="queue.html">FSharpChecker operations queue</a>) |
| 50 | +will be one of these projects. When analyzing large collections of projects, this cache usually occupies by far the most memory. |
| 51 | +Increasing the size of this cache can dramatically decrease incremental computation of project-wide checking, or of checking |
| 52 | +individual files within a project, but can very greatly increase memory usage.</p> |
| 53 | +</li> |
| 54 | +<li><p><code>braceMatchCache</code> - an MRU cache of size <code>braceMatchCacheSize</code> (default = 5) keeping the results of calls to MatchBraces, keyed by filename, source and project options.</p></li> |
| 55 | +<li> |
| 56 | +<p><code>parseFileInProjectCache</code> - an MRU cache of size <code>parseFileInProjectCacheSize</code> (default = 2) keeping the results of ParseFileInProject, |
| 57 | +keyed by filename, source and project options.</p> |
| 58 | +</li> |
| 59 | +<li> |
| 60 | +<p><code>parseAndCheckFileInProjectCache</code> - an MRU cache of size <code>incrementalTypeCheckCacheSize</code> (default = 5) keeping the results of |
| 61 | +ParseAndCheckFileInProject, CheckFileInProject and/or CheckFileInProjectIfReady. This is keyed by filename, file source |
| 62 | +and project options. The results held in this cache are only returned if they would reflect an accurate parse and check of the |
| 63 | +file.</p> |
| 64 | +</li> |
| 65 | +<li> |
| 66 | +<p><code>parseAndCheckFileInProjectCachePossiblyStale</code> - a somewhat peculiar MRU cache of size <code>incrementalTypeCheckCacheSize</code> (default = 5) |
| 67 | +keeping the results of ParseAndCheckFileInProject, CheckFileInProject and CheckFileInProjectIfReady, |
| 68 | +keyed by filename and project options. This cache is accessed by TryGetRecentTypeCheckResultsForFile. Because the results |
| 69 | +are accessed regardless of the content of the file, the checking results returned may be "stale".</p> |
| 70 | +</li> |
| 71 | +<li><p><code>getToolTipTextCache</code> - an aged lookup cache of strong size <code>getToolTipTextSize</code> (default = 5) computing the results of GetToolTipText.</p></li> |
| 72 | +<li> |
| 73 | +<p><code>ilModuleReaderCache</code> - an aged lookup of weak references to "readers" for references .NET binaries. Because these |
| 74 | +are all weak references, you can generally ignore this cache, since its entries will be automatically collected. |
| 75 | +Strong references to binary readers will be kept by other FCS data structures, e.g. any project checkers, symbols or project checking results.</p> |
| 76 | +<p>In more detail, the bytes for referenced .NET binaries are read into memory all at once, eagerly. Files are not left |
| 77 | +open or memory-mapped when using FSharpChecker (as opposed to FsiEvaluationSession, which loads assemblies using reflection). |
| 78 | +The purpose of this cache is mainly to ensure that while setting up compilation, the reads of mscorlib, FSharp.Core and so on |
| 79 | +amortize cracking the DLLs.</p> |
| 80 | +</li> |
| 81 | +<li> |
| 82 | +<p><code>frameworkTcImportsCache</code> - an aged lookup of strong size 8 which caches the process of setting up type checking against a set of system |
| 83 | +components (e.g. a particular version of mscorlib, FSharp.Core and other system DLLs). These resources are automatically shared between multiple |
| 84 | +project checkers which happen to reference the same set of system assemblies.</p> |
| 85 | +</li> |
| 86 | +</ul> |
| 87 | +<p>Profiling the memory used by the various caches can be done by looking for the corresponding static roots in memory profiling traces.</p> |
| 88 | +<p>The sizes of some of these caches can be adjusted by giving parameters to FSharpChecker. Unless otherwise noted, |
| 89 | +the cache sizes above indicate the "strong" size of the cache, where memory is held regardless of the memory |
| 90 | +pressure on the system. Some of the caches can also hold "weak" references which can be collected at will by the GC.</p> |
| 91 | +<blockquote> |
| 92 | +<p>Note: Because of these caches, uou should generally use one global, shared FSharpChecker for everything in an IDE application.</p> |
| 93 | +</blockquote> |
| 94 | +<h2><a name="Low-Memory-Condition" class="anchor" href="#Low-Memory-Condition">Low-Memory Condition</a></h2> |
| 95 | +<p>Version 1.4.0.8 added a "maximum memory" limit specified by the <code>MaxMemory</code> property on FSharpChecker (in MB). If an FCS project operation |
| 96 | +is performed (see <code>CheckMaxMemoryReached</code> in <code>service.fs</code>) and <code>System.GC.GetTotalMemory(false)</code> reports a figure greater than this, then |
| 97 | +the strong sizes of all FCS caches are reduced to either 0 or 1. This happens for the remainder of the lifetime of the FSharpChecker object. |
| 98 | +In practice this will still make tools like the Visual Studio F# Power Tools usable, but some operations like renaming across multiple |
| 99 | +projects may take substantially longer.</p> |
| 100 | +<p>By default the maximum memory trigger is disabled, see <code>maxMBDefault</code> in <code>service.fs</code>.</p> |
| 101 | +<p>Reducing the FCS strong cache sizes does not guarantee there will be enough memory to continue operations - even holding one project |
| 102 | +strongly may exceed a process memory budget. It just means FCS may hold less memory strongly.</p> |
| 103 | +<p>If you do not want the maximum memory limit to apply then set MaxMemory to System.Int32.MaxValue.</p> |
| 104 | +<h2><a name="Summary" class="anchor" href="#Summary">Summary</a></h2> |
| 105 | +<p>In this design note, you learned that the FSharpChecker component keeps a set of caches in order to support common |
| 106 | +incremental analysis scenarios reasonably efficiently. They correspond roughly to the original caches and sizes |
| 107 | +used by the Visual F# Tools, from which the FSharpChecker component derives.</p> |
| 108 | +<p>In long running, highly interactive, multi-project scenarios you should carefully |
| 109 | +consider the cache sizes you are using and the tradeoffs involved between incremental multi-project checking and memory usage.</p> |
| 110 | + |
| 111 | + |
| 112 | + </div> |
| 113 | + <div class="span3"> |
| 114 | + <a href="https://nuget.org/packages/FSharp.Compiler.Service"> |
| 115 | + <img src="./images/logo.png" style="width:140px;height:140px;margin:10px 0px 0px 35px;border-style:none;" /> |
| 116 | + </a> |
| 117 | + <ul class="nav nav-list" id="menu"> |
| 118 | + <li class="nav-header"> |
| 119 | + <a href="./ja/index.html" class="nflag"><img src="./images/ja.png" /></a> |
| 120 | + <a href="./index.html" class="nflag nflag2"><img src="./images/en.png" /></a> |
| 121 | + F# Compiler Services |
| 122 | + </li> |
| 123 | + <li><a href="./index.html">Home page</a></li> |
| 124 | + <li class="divider"></li> |
| 125 | + <li><a href="https://www.nuget.org/packages/FSharp.Compiler.Service">Get Library via NuGet</a></li> |
| 126 | + <li><a href="http://github.com/fsharp/FSharp.Compiler.Service">Source Code on GitHub</a></li> |
| 127 | + <li><a href="http://github.com/fsharp/FSharp.Compiler.Service/blob/master/LICENSE">License</a></li> |
| 128 | + <li><a href="http://github.com/fsharp/FSharp.Compiler.Service/blob/master/RELEASE_NOTES.md">Release Notes</a></li> |
| 129 | + |
| 130 | + <li class="nav-header">Getting started</li> |
| 131 | + <li><a href="./index.html">Home page</a></li> |
| 132 | + <li><a href="./devnotes.html">Developer notes</a></li> |
| 133 | + <li><a href="./fsharp-readme.html">F# compiler readme</a></li> |
| 134 | + |
| 135 | + <li class="nav-header">Available services</li> |
| 136 | + <li><a href="./tokenizer.html">F# Language tokenizer</a></li> |
| 137 | + <li><a href="./untypedtree.html">Processing untyped AST</a></li> |
| 138 | + <li><a href="./editor.html">Using editor (IDE) services</a></li> |
| 139 | + <li><a href="./symbols.html">Using resolved symbols</a></li> |
| 140 | + <li><a href="./typedtree.html">Using resolved expressions</a></li> |
| 141 | + <li><a href="./project.html">Whole-project analysis</a></li> |
| 142 | + <li><a href="./interactive.html">Embedding F# interactive</a></li> |
| 143 | + <li><a href="./compiler.html">Embedding F# compiler</a></li> |
| 144 | + <li><a href="./filesystem.html">Virtualized file system</a></li> |
| 145 | + |
| 146 | + <li class="nav-header">Design Notes</li> |
| 147 | + <li><a href="./queue.html">The FSharpChecker operations queue</a></li> |
| 148 | + <li><a href="./caches.html">The FSharpChecker caches</a></li> |
| 149 | + <li><a href="./corelib.html">Notes on FSharp.Core.dll</a></li> |
| 150 | + |
| 151 | + <li class="nav-header">Documentation</li> |
| 152 | + <li><a href="./reference/index.html">API Reference</a> |
| 153 | + </li> |
| 154 | + </ul> |
| 155 | + </div> |
| 156 | + </div> |
| 157 | + </div> |
| 158 | + <a href="http://github.com/fsharp/FSharp.Compiler.Service"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"></a> |
| 159 | + </body> |
| 160 | + </html> |
0 commit comments