Rubberduck
Rubberduck copied to clipboard
Holy RAM, batman! (Out of memory errors and excessively high memory usage)
After observing random "System resources exceeded" or "Out of memory" with my usercode which didn't quite make sense, I later ran quick fixes. After applying changes, I went to start the application and immediately got the System resources exceeded *despite have NOT run any VBA code`.
Suspicious, I restarted Access, then opened Access. Noted the working set memory at 8MB. Launch open VBA, the working set rockets to 175MB working set memory. Run parse, the working set goes up to 300 MB! Open quick inspector, and refresh, the working set climbs to 475 MB!
I might be going out on a limb but it sure looks like to me something's hemorrhaging hemorrhages.
Smells like a memory leak indeed. However note that much of the performance comes from caching - trade-off is between memory consumption and performance. Not saying there's no room to consume less memory for the same performance, but RD isn't, and never was, intended to be lightweight at all.
@retailcoder I'm totally down with RD never ever being lightweight. I wouldn't expect it, really.
However, I think it is worthwhile to point out that I can load 2,282,482 records in an Access datasheet and only have 25-30 MB in the working set. I can do other operations such as grouping much faster. You can try it out yourself by playing w/ FactSale table from this package: http://powerpivotsdr.codeplex.com/releases/view/46355 Note: technically, that's a lie - Access merely makes it looks like it loaded that many but it in fact maintains a scrolling window, having ~100 records filling in background and partially in response to user's action; it only needs to load 2 million keys, then transverse the chain to read the whole data.
I know this is very an apple to oranges comparison because I'm comparing a C++ application against C# application but I also point out that Access is fundamentally disk-based which is an order of magnitude slower than RAM and we still see good performance nonetheless.
I am not well-qualified to offer criticism but it does not appear to me we are using database but primarily in-memory collections. That makes me think many operations we are doing are always going to be expensive because it isn't a database and has no index to reduce the search space. It might be possible that RD would benefit more from using sqlite or something similar than caching service that is entirely in memory, given the large number of objects RD needs to have and comparatively only a small subset get invalidated after some event. Having tables and indexes would allow you to quickly prune and re-populate the subsets, likely in spite of saving to a much much slower subsystem.
Just a thought.
it isn't a database and has no index to reduce the search space.
Most of our lookups are hash matches in dictionary keys, an essentially O(1) operation that completes pretty much instantaneously regardless of how many thousands of keys we're looking at... And it's all in RAM indeed. An empty project with standard library references is working with ~50-60K declarations, and we cache a number of aggregates too. Each declaration is an object that contains information about its name, type, accessibility, references in user code, etc.; this metadata is fundamental for Rubberduck to understand the code.
To be honest it never even occurred to me that we could use a database and literally query the code. That's a very, very interesting idea...
In that case, if you do use a database, your ideal database should support hash indexes as to keep the O(1) operation. I can't recall off the cuff if sqlite has hash index. I wrongly(?) assumed that you were also doing querying because in the quick fix inspection window, we group stuff, and display only first 100. That's an example of querying where a B-tree index can help cut down on the search space because you don't want to literally loop each single member of the collection in this case. You only want a scrolling window of data.
From reading I did whenever you invalidate a module reference, you have to delete all references from that module, then re-build it. That's another example where a B-tree index would win out on a hash index -- just delete all references with module = "x", done in a sequential scan. Besides, it's much easier to optimize a database than it is code (at least that's the case for me).
Oh, I was merely talking about the DeclarationFinder, which is where most queries begin; inspections use it to get all user declarations, or all byref parameters, or line labels, or variables, whatever the inspections inspect. Using a database backend would be a complete gsme changer... I'm giving this some serious thought.
FWIW @bclothier sqlite does not maintain a hash-index. It does maintain some indexes, but it's IMO not suited to replace the mass of frequently updated information that Rubberduck needs. SQLite is simply not intended for the load of more or less completely refreshing a whole database whenever RD reparses.
Just to give an apple-pear comparison... I fired up VIsual Studio 2015 and loaded Rubberduck solution (what else?).
Initial loading took about ~245 MB of working set.
Building it bumps it up to ~280 MB.
Running code analysis on it adds some more up to ~315-320 MB.
This is keeping in mind that Visual Studio is much more complicated and it likely has to handle far more references & declaration to support code analysis (which might not be as sophisticated as Resharper). That said, it's safe to say it doesn't need to increase by more than 100MB just to parse or to do inspection.
Whether Visual Studio is doing this all in-memory or not, I don't know.
That said, I question whether you really need to "completely refreshing a whole database whenever RD parses." Given that I can only type so fast and that I can only change one module at a time (which remains true even if I'm using VBIDE to automate my changes), you're always going to be invalidating a subset. Even if I clicked Parse, it'd be still more logical to parse what changed unless I explicitly force a full parse (e.g. akin to Rebuild method in Visual Studio). So tossing the whole database should be, IMO, rare and explicit.
And if you are always going to work in subsets, you aren't going to get good performance from in-memory collections that can only support hash indexing; you need a range seek so you can enumerate only that subset, done.
Maybe your answer is a in-memory collection that supports B-tree indices. Maybe it's really just a boring old memory leak.I don't know. But I really don't think we need that much RAM based on what I've observed.
Visual Studio is also at version 15 or so (we work with v6.0 essentially), with Roslyn being the single most efficient compiler/analyzer out there, written by an army of brains. We are not Microsoft, or JetBrains, and we're not hundreds of contributors, we're a handful, doing this part-time when it's possible. It is thoroughly unfair a comparison. VS & Roslyn are integrated, they can parse a single modified line of code. Rubberduck does what it can with the shitty VBIDE API, and parses with ANTLR, and because it's not integrated the smallest possible granular unit we can parse is an entire module - anything else and we can kiss good-bye token positions. So yes, a subset - but not half as granular as a single modified line of code.
That said I don't think we would have to ditch & recreate the whole database every time. A db could be a very interesting solution to project metadata, per-project and per-user settings, and for storage of the thousands of COM declarations, which definitely make up the bulk of the RAM we're eating up.
@retailcoder I apologize if I've overstepped. You're absolutely right that VS has much more resources behind it than RD does, so what RD people achieved is nothing short of phenomenal. I clearly didn't think about ANTLR vs Roslyn. I did want to get a sense of what is possible, hence my comparison. That said, I'll stop putting on big britches now.
@bclothier I didn't mean to come off rude or even annoyed - at the end of the day RD is eating up a ton of RAM, and likely leaking some; memory leaks are a critical issue, and embedding an actual database isn't a completely crazy idea at all. I think I'd go with SQL Server Express though. Gotta think about how to deploy RD to the website too (that online parser in the inspections page is performing terribly ATM).
Thanks for your ideas! 😄

#3405 could be related? We should reevaluate this after a fix for that is merged
Just to follow up on a newer version (admittedly a dev version of 2.1.6542.12529)
Access loaded (34 MB) VBE loaded (253 MB) After parsing (450 MB) Loading Code Inspector (460 MB) After few Fix (Ignore Once) (523 MB) + keeps increasing for each subsequent Fixes
I think there's a clear memory leak with the Fix. When I got to the "Loading Code Inspector", the CI toolwindow was much more responsive than when I originally reported the issue, but it does get slower and slower each time I fix an inspection.
Addendum from the chat where Mat asked about whether it's quickfix or reparse --- I noticed that the same project had receded from its original peak which was 641 MB to about 500 MB. Each parse adds 20 MB, and doing them in rapid succession can keep adding more and more but after a bit enough, they do get released, which is likely the result of GC's delayed cleanup.
As per a suggestion in the chat, here's the test again with code explorer totally unwired from the startup process...
Access loaded (35 MB) VBE loaded (230 MB) After parsing (445 MB)
Seems to suggest it's not the UI but the inspections themselves or the parsing that's expensive.
Addendum: As a comparison, loading the same project but with Rubberduck disabled (there are other addins still enabled), the memory climbs from 35MB to ~115MB, suggesting that pre-parse, RD adds ~100 MB to load.
As this is banging around in the background, a thought occurred to me. If a change is made to use a DB in the background, many things could be stored in the DB permanently. There's no need to reparse and rebuild all the objects in EXCEL.EXE until/unless you change versions of Office. Many of the DLLs, OLBs, TLBs, etc that are referenced in a project don't change very often (if ever).
A meta-metadata tag could be kept which indicates which version is being referenced in a project, and if that version is already in the DB, it never needs to be parsed. I would presume that should speed up parse times considerably. It might increase RD ship size by including a pre-populated DB, but that, IMHO, is a minor concern, or, RD could build the library of pre-parsed references and never touch them again (until a version flag is updated).
Keep in mind that while we certainly could store the metadata, this means we are now trading performance for footprint. As already discussed in the first few posts of the issue, reading data off a hard drive (usually the slowest subsystem of a computer) is glacial in comparison to reading the same off a memory address within RAM. At very least, we would be able to use to load the data quickly without going through the motions of parsing the references of built-in libraries. However, it still will end up in memory if we want good performance.
We need to have a concrete description of what changes we need to make to make this better to make the discussion meaningful.
Since I love idiotic suggestions, but ones that could solve problems, couldn't we use some sort of in-memory DB like SQLite ? I don't know how it would perform against a regular hashed table, but it could provide a mean to better organize the data, and then prevent leakage, and you don't have the speed limit of a regular HDD.
In case of a rebuild, just rebuild the DB. I don't know, in the case of that project, if the DB would, in the end, result in less RAM usage though.
https://www.sqlite.org/inmemorydb.html
Edit : nvm, by the time I wrote this post, from the time I had the page opened, bclothier wrote his post
@FuSoftware that's far from idiotic :wink:
@retailcoder Oh, I somehow missed it ! Once I go back to a proper computer, I'll gladly join the project, seems quite interesting, and pretty active so far !
Ha! I love the suggestion. I did suggest database before but not sure if I explicitly suggested an in-memory database.
To get the best use, we would need to index the properties we use the most in the inspections and whatever. But there's also the other thing --- if you read earlier, @retailcoder points out that most of lookups are hash lookup and therefore a O(1) operation. Hard to beat that. And by introducing a database, we pay a bit more in the index maintenance. This might be very good thing for the non-user-defined, since they won't change, but not so helpful for user-defined objects.
To make it even more concrete, we should look closely at the Declaration and IdentifierReference objects --- those are what we are creating in tens of thousands for both user-defined and built-in. If we can find an access that we can substantially benefit from a B-tree index, then great! But we need to be able to describe that exactly before we can put it in practice.
@FuSoftware do you have a Stack Exchange account? Our "war room" is on Code Review SE chat - I have moderator privs until the CR elections, so I can still grant you write access if you don't have 20 rep yet. Join us anytime!
I have the 100 credit bonus on CR because of my 500 SO rep, so it should be all good ! And yeah, again I'll have to take a proper look at the source. I thing my 16 GB PC at home should handle RD :stuck_out_tongue:
I don't think that the overhead of having a DB would be too significant if the queries are made properly. I'll take some dime understanding how the current RD works, then I may be able to make proper suggestions ^^
Now, that this topic has come up again, I realized that I never posted my observations with the memory profiler here. (Apparently, I only posted them in chat.)
I have run RD again under the dotMemory memory profiler. On my system, starting the VBE in Excel immediately leads to the consumption of about 300MB of unmanaged memory, which stays more or less stable over the entire lifetime of the process.
Unfortunately, dotMemory cannot profile unmanaged memory and I do not have another memory profiler. However, there are several natural causes for the memory consumption:
- The CLR itself has to be loaded by the first .NET add-in running in the VBA.
- The CLR has to store JITed code, i.e. RD itself.
- WPF uses DirectX caches, which are unmanaged. In particular, bitmaps get cached as unmanaged memory, which is confusing the GC. (The managed object is very small.)
To give a bit more background why the WPF windows might play a role here, although they usually do not seem to be open, I would like to remind everybody of a few quirks of the VBE and our setup:
- Generally, the VBE closes windows only on shutdown. At all other times, it just hides the windows offscreen. (I do not remember whether it resizes them, too, but I think it does not minimize them) Thus, once a window is open, it stays open.
- We have to open a window and make it visible to enforce the correct starting dimensions and position.
- Our five main windows get created once during the RD startup.
Regrading the managed memory, this is really mostly connected to the declarations and parse trees. Consequently, having a lot of references to large libraries causes a high memory load. Serialized to a text file, the declarations in the Excel object library alone are larger than 100MB and the HTML reference is several hundred MB in size, IIRC.
To add a bit more about the "hanging" issue that happens once the RAM eats a certain amount and you close the software, but it doesn't close.
I had that earlier, it went from 500+ MB to 650 MB RAM while closing, then it went back to 500 MB for a few seconds before going back up to 650MB.
At that point, WerFault.exe (the Windows Error Logger) started working, eating one of my cores (probably dumping the problem somewhere). It then went quite slow (2% CPU) for a good minute and closed, then 2 minutes after that, Excel closed.
If that has already happened, and you know where the log file could be (I have a Windows 7 32 bits without SP1), I will gladly share it to make the issue easier to understand !
@FuSoftware it's generally at the %APPDATA%\Rubberduck\Logs. This presumes you changed the logging level. Default is None; if you didn't, go to Rubberduck -> Settings, and set it to Trace (the most verbose level).
Erm, @Vogel612 suggested that it might be the logs from WerFault.exe you're looking for - if so.... see if this helps
No, it wasn't a Rubberduck Crash, the logs aren't here. I found the WER log regarding the crash in AppData\Local\Microsoft\Windows\WER\ReportQueue though. It's pretty huge so I'll upload it somewhere and share the link
Linking chat.
Is there anything I can do to improve this? e.g. set LARGEADDRESSAWARE on the VB6.exe? We have 700 modules, forms, classes and usercontrols in one project and RD is very slow and then stops.
2019-06-03 12:51:04.7031;ERROR-2.4.1.4627;Rubberduck.Parsing.VBA.ParseCoordinator;Unexpected exception thrown in parsing run. (thread 5).;System.AggregateException: One or more errors occurred. ---> System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
at Antlr4.Runtime.Atn.ATNConfig.Transform(ATNState state, PredictionContext context, SemanticContext semanticContext, Boolean checkNonGreedy, LexerActionExecutor lexerActionExecutor)
at Antlr4.Runtime.Atn.ATNConfig.Transform(ATNState state, Boolean checkNonGreedy)
at Antlr4.Runtime.Atn.ParserATNSimulator.GetEpsilonTarget(ATNConfig config, Transition t, Boolean collectPredicates, Boolean inContext, PredictionContextCache contextCache, Boolean treatEofAsEpsilon)
at Antlr4.Runtime.Atn.ParserATNSimulator.Closure(ATNConfig config, ATNConfigSet configs, ATNConfigSet intermediate, HashSet`1 closureBusy, Boolean collectPredicates, Boolean hasMoreContexts, PredictionContextCache contextCache, Int32 depth, Boolean treatEofAsEpsilon)
at Antlr4.Runtime.Atn.ParserATNSimulator.Closure(ATNConfigSet sourceConfigs, ATNConfigSet configs, Boolean collectPredicates, Boolean hasMoreContext, PredictionContextCache contextCache, Boolean treatEofAsEpsilon)
at Antlr4.Runtime.Atn.ParserATNSimulator.ComputeTargetState(DFA dfa, DFAState s, ParserRuleContext remainingGlobalContext, Int32 t, Boolean useContext, PredictionContextCache contextCache)
at Antlr4.Runtime.Atn.ParserATNSimulator.ComputeReachSet(DFA dfa, SimulatorState previous, Int32 t, PredictionContextCache contextCache)
at Antlr4.Runtime.Atn.ParserATNSimulator.ExecATN(DFA dfa, ITokenStream input, Int32 startIndex, SimulatorState initialState)
at Antlr4.Runtime.Atn.ParserATNSimulator.ExecDFA(DFA dfa, ITokenStream input, Int32 startIndex, SimulatorState state)
at Antlr4.Runtime.Atn.ParserATNSimulator.AdaptivePredict(ITokenStream input, Int32 decision, ParserRuleContext outerContext, Boolean useContext)
at Antlr4.Runtime.Atn.ParserATNSimulator.ExecDFA(DFA dfa, ITokenStream input, Int32 startIndex, SimulatorState state)
at Antlr4.Runtime.Atn.ParserATNSimulator.AdaptivePredict(ITokenStream input, Int32 decision, ParserRuleContext outerContext, Boolean useContext)
at Antlr4.Runtime.Atn.ParserATNSimulator.AdaptivePredict(ITokenStream input, Int32 decision, ParserRuleContext outerContext)
at Rubberduck.Parsing.Grammar.VBAParser.whiteSpace() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 21242
at Rubberduck.Parsing.Grammar.VBAParser.individualNonEOFEndOfStatement() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 20323
at Rubberduck.Parsing.Grammar.VBAParser.endOfStatement() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 20232
at Rubberduck.Parsing.Grammar.VBAParser.moduleConfigElement() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 1113
at Rubberduck.Parsing.Grammar.VBAParser.moduleConfig() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 844
at Rubberduck.Parsing.Grammar.VBAParser.moduleConfig() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 832
at Rubberduck.Parsing.Grammar.VBAParser.module() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 439
at Rubberduck.Parsing.Grammar.VBAParser.startRule() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 334
at Rubberduck.Parsing.VBA.Parsing.VBATokenStreamParser.Parse(ITokenStream tokenStream, PredictionMode predictionMode, IParserErrorListener errorListener) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\VBATokenStreamParser.cs:line 21
at Rubberduck.Parsing.VBA.Parsing.TokenStreamParserBase.ParseLl(String moduleName, ITokenStream tokenStream, CodeKind codeKind) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\TokenStreamParserBase.cs:line 75
at Rubberduck.Parsing.VBA.Parsing.TokenStreamParserBase.ParseWithFallBack(String moduleName, CommonTokenStream tokenStream, CodeKind codeKind) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\TokenStreamParserBase.cs:line 52
at Rubberduck.Parsing.VBA.Parsing.TokenStreamParserBase.Parse(String moduleName, CommonTokenStream tokenStream, CodeKind codeKind, ParserMode parserMode) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\TokenStreamParserBase.cs:line 32
at Rubberduck.Parsing.VBA.Parsing.TokenStreamParserStringParserAdapterWithPreprocessing.Parse(String moduleName, String projectId, String code, CancellationToken token, CodeKind codeKind, ParserMode parserMode) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\TokenStreamParserStringParserAdapterWithPreprocessing.cs:line 29
at Rubberduck.Parsing.VBA.Parsing.ModuleParser.AttributesPassResults(QualifiedModuleName module, CancellationToken token) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ModuleParser.cs:line 156
at Rubberduck.Parsing.VBA.Parsing.ModuleParser.ParseInternal(QualifiedModuleName module, CancellationToken cancellationToken, TokenStreamRewriter rewriter, Guid taskId) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ModuleParser.cs:line 96
at Rubberduck.Parsing.VBA.Parsing.ModuleParser.Parse(QualifiedModuleName module, CancellationToken cancellationToken, TokenStreamRewriter rewriter) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ModuleParser.cs:line 74
at Rubberduck.Parsing.VBA.Parsing.ParseRunnerBase.ParseModule(QualifiedModuleName module, CancellationToken token) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ParseRunnerBase.cs:line 60
at Rubberduck.Parsing.VBA.Parsing.ParseRunner.<>c__DisplayClass2_0.<ParseModules>b__0(QualifiedModuleName module) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ParseRunner.cs:line 43
at System.Threading.Tasks.Parallel.<>c__DisplayClass42_0`2.<PartitionerForEachWorker>b__1()
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
at System.Threading.Tasks.Task.<>c__DisplayClass176_0.<ExecuteSelfReplicating>b__0(Object <p0>)
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at System.Threading.Tasks.Task.Wait()
at System.Threading.Tasks.Parallel.PartitionerForEachWorker[TSource,TLocal](Partitioner`1 source, ParallelOptions parallelOptions, Action`1 simpleBody, Action`2 bodyWithState, Action`3 bodyWithStateAndIndex, Func`4 bodyWithStateAndLocal, Func`5 bodyWithEverything, Func`1 localInit, Action`1 localFinally)
at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](IEnumerable`1 source, ParallelOptions parallelOptions, Action`1 body, Action`2 bodyWithState, Action`3 bodyWithStateAndIndex, Func`4 bodyWithStateAndLocal, Func`5 bodyWithEverything, Func`1 localInit, Action`1 localFinally)
at System.Threading.Tasks.Parallel.ForEach[TSource](IEnumerable`1 source, ParallelOptions parallelOptions, Action`1 body)
at Rubberduck.Parsing.VBA.Parsing.ParseRunner.ParseModules(IReadOnlyCollection`1 modules, CancellationToken token) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ParseRunner.cs:line 53
at Rubberduck.Parsing.VBA.ParsingStageService.ParseModules(IReadOnlyCollection`1 modulesToParse, CancellationToken token) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\ParsingStageService.cs:line 67
at Rubberduck.Parsing.VBA.ParseCoordinator.ExecuteCommonParseActivities(IReadOnlyCollection`1 toParse, IReadOnlyCollection`1 toReresolveReferencesInput, IReadOnlyCollection`1 newProjectIds, CancellationToken token) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\ParseCoordinator.cs:line 301
at Rubberduck.Parsing.VBA.ParseCoordinator.ParseAllInternal(Object requestor, CancellationToken token) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\ParseCoordinator.cs:line 506
at Rubberduck.Parsing.VBA.ParseCoordinator.ParseAll(Object requestor) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\ParseCoordinator.cs:line 415
---> (Inner Exception #0) System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
at Antlr4.Runtime.Atn.ATNConfig.Transform(ATNState state, PredictionContext context, SemanticContext semanticContext, Boolean checkNonGreedy, LexerActionExecutor lexerActionExecutor)
at Antlr4.Runtime.Atn.ATNConfig.Transform(ATNState state, Boolean checkNonGreedy)
at Antlr4.Runtime.Atn.ParserATNSimulator.GetEpsilonTarget(ATNConfig config, Transition t, Boolean collectPredicates, Boolean inContext, PredictionContextCache contextCache, Boolean treatEofAsEpsilon)
at Antlr4.Runtime.Atn.ParserATNSimulator.Closure(ATNConfig config, ATNConfigSet configs, ATNConfigSet intermediate, HashSet`1 closureBusy, Boolean collectPredicates, Boolean hasMoreContexts, PredictionContextCache contextCache, Int32 depth, Boolean treatEofAsEpsilon)
at Antlr4.Runtime.Atn.ParserATNSimulator.Closure(ATNConfigSet sourceConfigs, ATNConfigSet configs, Boolean collectPredicates, Boolean hasMoreContext, PredictionContextCache contextCache, Boolean treatEofAsEpsilon)
at Antlr4.Runtime.Atn.ParserATNSimulator.ComputeTargetState(DFA dfa, DFAState s, ParserRuleContext remainingGlobalContext, Int32 t, Boolean useContext, PredictionContextCache contextCache)
at Antlr4.Runtime.Atn.ParserATNSimulator.ComputeReachSet(DFA dfa, SimulatorState previous, Int32 t, PredictionContextCache contextCache)
at Antlr4.Runtime.Atn.ParserATNSimulator.ExecATN(DFA dfa, ITokenStream input, Int32 startIndex, SimulatorState initialState)
at Antlr4.Runtime.Atn.ParserATNSimulator.ExecDFA(DFA dfa, ITokenStream input, Int32 startIndex, SimulatorState state)
at Antlr4.Runtime.Atn.ParserATNSimulator.AdaptivePredict(ITokenStream input, Int32 decision, ParserRuleContext outerContext, Boolean useContext)
at Antlr4.Runtime.Atn.ParserATNSimulator.ExecDFA(DFA dfa, ITokenStream input, Int32 startIndex, SimulatorState state)
at Antlr4.Runtime.Atn.ParserATNSimulator.AdaptivePredict(ITokenStream input, Int32 decision, ParserRuleContext outerContext, Boolean useContext)
at Antlr4.Runtime.Atn.ParserATNSimulator.AdaptivePredict(ITokenStream input, Int32 decision, ParserRuleContext outerContext)
at Rubberduck.Parsing.Grammar.VBAParser.whiteSpace() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 21242
at Rubberduck.Parsing.Grammar.VBAParser.individualNonEOFEndOfStatement() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 20323
at Rubberduck.Parsing.Grammar.VBAParser.endOfStatement() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 20232
at Rubberduck.Parsing.Grammar.VBAParser.moduleConfigElement() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 1113
at Rubberduck.Parsing.Grammar.VBAParser.moduleConfig() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 844
at Rubberduck.Parsing.Grammar.VBAParser.moduleConfig() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 832
at Rubberduck.Parsing.Grammar.VBAParser.module() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 439
at Rubberduck.Parsing.Grammar.VBAParser.startRule() in C:\projects\rubberduck\Rubberduck.Parsing\obj\Release\net46\VBAParser.cs:line 334
at Rubberduck.Parsing.VBA.Parsing.VBATokenStreamParser.Parse(ITokenStream tokenStream, PredictionMode predictionMode, IParserErrorListener errorListener) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\VBATokenStreamParser.cs:line 21
at Rubberduck.Parsing.VBA.Parsing.TokenStreamParserBase.ParseLl(String moduleName, ITokenStream tokenStream, CodeKind codeKind) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\TokenStreamParserBase.cs:line 75
at Rubberduck.Parsing.VBA.Parsing.TokenStreamParserBase.ParseWithFallBack(String moduleName, CommonTokenStream tokenStream, CodeKind codeKind) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\TokenStreamParserBase.cs:line 52
at Rubberduck.Parsing.VBA.Parsing.TokenStreamParserBase.Parse(String moduleName, CommonTokenStream tokenStream, CodeKind codeKind, ParserMode parserMode) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\TokenStreamParserBase.cs:line 32
at Rubberduck.Parsing.VBA.Parsing.TokenStreamParserStringParserAdapterWithPreprocessing.Parse(String moduleName, String projectId, String code, CancellationToken token, CodeKind codeKind, ParserMode parserMode) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\TokenStreamParserStringParserAdapterWithPreprocessing.cs:line 29
at Rubberduck.Parsing.VBA.Parsing.ModuleParser.AttributesPassResults(QualifiedModuleName module, CancellationToken token) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ModuleParser.cs:line 156
at Rubberduck.Parsing.VBA.Parsing.ModuleParser.ParseInternal(QualifiedModuleName module, CancellationToken cancellationToken, TokenStreamRewriter rewriter, Guid taskId) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ModuleParser.cs:line 96
at Rubberduck.Parsing.VBA.Parsing.ModuleParser.Parse(QualifiedModuleName module, CancellationToken cancellationToken, TokenStreamRewriter rewriter) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ModuleParser.cs:line 74
at Rubberduck.Parsing.VBA.Parsing.ParseRunnerBase.ParseModule(QualifiedModuleName module, CancellationToken token) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ParseRunnerBase.cs:line 60
at Rubberduck.Parsing.VBA.Parsing.ParseRunner.<>c__DisplayClass2_0.<ParseModules>b__0(QualifiedModuleName module) in C:\projects\rubberduck\Rubberduck.Parsing\VBA\Parsing\ParseRunner.cs:line 43
at System.Threading.Tasks.Parallel.<>c__DisplayClass42_0`2.<PartitionerForEachWorker>b__1()
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)
at System.Threading.Tasks.Task.<>c__DisplayClass176_0.<ExecuteSelfReplicating>b__0(Object <p0>)<---