Rubberduck: Insufficient memory

Created on 19 Dec 2016  路  16Comments  路  Source: rubberduck-vba/Rubberduck

I ran into an Insufficient memory exception. The Rubberduck log doesn't show a trace of this. It shows a Microsoft .NET Framework dialog box with the exception message:

See the end of this message for details on invoking
just-in-time (JIT) debugging instead of this dialog box.

*** Exception Text ***
System.OutOfMemoryException: Insufficient memory to continue the execution of the program.
at System.Windows.Media.Composition.DUCE.Channel.SyncFlush()
at System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean enableRenderTarget, Nullable`1 channelSet)
at System.Windows.Interop.HwndTarget.UpdateWindowPos(IntPtr lParam)
at System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.SafeNativeMethods.SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, Int32 x, Int32 y, Int32 cx, Int32 cy, Int32 flags)
at System.Windows.Forms.Integration.ElementHost.SetHWndSourceWindowPos()
at System.Windows.Forms.Integration.ElementHost.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

bug feature-inspections user-interface

Most helpful comment

zen

All 16 comments

Wah, WTF! Is there a memory leak in WPF interop?

I'm sorry for this. Rubberduck is in itself an excellent and much needed tool!

Ok, so we have a repro with a truckload of inspection results; the inspection completes (eventually), but the grid blows up with an OOM exception trying to display all the results.

How about we limit the displayed results to, say, 255 per inspection?

I don't like setting an arbitrary limit like that though. The grid will perfectly handle 5000 results of one inspection type, but then if all 30-some inspections issue 5000 results then there will be a problem.

Not sure what the best UX would be.

@retailcoder where exactly do we OOM? I daresay it's just when displaying the results. As such it might be advisable to limit the number of total results before limiting the number of results per inspection.

it might be conceivable to have a "rolling" limit for inspection results depending on the ratios of actually reported inspectons.

@Vogel612 exactly - it's the grid that can't handle that many results. However the inspections run asynchronously, and the results are sorted in the XAML, so if we limit the total number of results there's a reasonable chance that we won't be able to display a result for all triggered inspections.

I think we could make the Inspector a bit smarter, and exclude individual results from inspections that spawn more than, say, 1024 results. Yet we could tweak the XAML template and introduce some AggregateInspectionResult type that would still show up, and look something like this:

(warning) Implicit reference to ActiveSheet: 14,732 results [disable this inspection]

Aggregated results would have more limited functionality (no double-click navigation (, no quickfixes?), but we could still show the inspection's meta-description in the bottom panel), but then we wouldn't blow up the GroupingGrid, and we'd still be reporting all issues.

@Vogel612 - When I was testing this, RD didn't flinch at generating 30,000 inspection results. It obviously _took_ a while, but the memory overhead for a result object isn't really that high. With a reasonably sized inspection window, each result is being rendered to a ~800px by 27px bitmap as it's drawn to the form. That's ~86kb per result pushed at the GDI. My understanding of how a scrollable WPF container works is that it actually renders the entire thing and then windows it using the scrollbar. So 30K results comes out to right around 2.4GB for that control _alone_.

Just thinking here folks. So we could setup to have a summary of inspections (a listing totals per inspection type) and somewhere in the grid the individual "detail" which potentially like Comintern indicated up to 30,000 equal 2.4 Gb, would the settings be a good place to put some limit of say 500 as default at any one time similar to how database admin can restrict the fetch of memory pages to improve network performances for databases.

@PeterMTaylor I like the idea of adding that arbitrary limit to the inspection settings configuration page.

zen

Nice @ThunderFrame so I get to select strawberry flavour for small tweaks to see if it works with my user interface or a strong chocolate flavour for an all nighter major code change as a patch, so each flavour changes the default set arbitrary limit. Cool 馃槑

OK, before you do anything here, I want to stick my oar in. The first step, of course, is the figure out what is eating the memory. I don't know for sure, but is it possibly the quick fixes? Remember that it is on the books to generate the quick fixes lazily, so...

@Hosch250 the OOM stack trace is pretty explicit about what's blowing up.

NVM.

PR #2502 (and thus #2443) should work around this issue in a rather elegant way. Considering it fixed for now.

image

the default quick-fix for an inspection can be executed (double-click navigation and the "fix" button both only apply to the first result in the aggregate), and if the default fix can be executed in the project or module, the options are available - here I've just fixed 250 inspection results with 1 click, across 10 lines of code in the module:

image

It's pretty fun to watch actually. Makes me wish there was an Application.ScreenUpdating to toggle off...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

philippetev picture philippetev  路  3Comments

ThunderFrame picture ThunderFrame  路  3Comments

susnick picture susnick  路  3Comments

retailcoder picture retailcoder  路  3Comments

SteGriff picture SteGriff  路  3Comments