Locke
Locke

Reputation: 1165

WPF Applications in VSTO not being garbage collected

So, I'm building applications for Office (via VSTO's) with C# and WPF. I'm seeing that the WPF application (via memory profilers) is never collected after being launched.

I'm going as far as creating a new AppDomain for the WPF Application, launching it inside that AppDomain, and following the use, Unloading the AppDomain, but I still have objects around -- and my handles are still increasing in size.

Does anyone know of any strange behaviors of VSTO and WPF applications? My only guess is that for some reason, the WPF application is loaded on the UI thread shared by Office, so it never gets cleaned up...

Any thoughts on the increasing handles? I'm getting a lot of backlash from my client's deployment team that the "increasing handles are not acceptable."

EDIT:

Let me be clear -- the WPF applications are launched from the Ribbon, and they then produce output in the respective application, i.e. if in Excel, you'll enter information and it will then build a spreadsheet for you based on the information provided; if in PowerPoint, you'll enter information (in the WPF application launched from the ribbon) and it'll build a slide based on the information you provided.

Upvotes: 2

Views: 379

Answers (1)

Steve Jansen
Steve Jansen

Reputation: 9494

My understanding is that VSTO solutions (at least as of Visual Studio 2010) always use a default COM shim to load the VSTO add-in to a separate AppDomain. This isolation protects your add-in from any instability of other add-ins.

Perhaps your application's memory usage is growing in due to hidden runtime callable wrappers (RCWs) created when interacting with the VSTO host application (e.g., Excel)?

My first VSTO app initially relied on Marshal.ReleaseComObject() to free RCWs, however, I changed my approach to use below based on these blog articles:

I now use this approach to force the GC to

public static class OfficeHelper
{
  /// <summary>
  ///   Forces a GC to release unused run time callable wrappers around COM objects
  /// </summary>
  /// <example>
  ///   dynamic rcw;
  ///   try
  ///   {
  ///      rcw = Globals.ThisWorkbook.ActiveSheet;
  ///      // do something
  ///      // ...
  ///    }
  ///    finally
  ///    {
  ///      rcw = null;
  ///      OfficeHelper.Cleanup();
  ///    }
  /// </example>
  public static void Cleanup()
  {
    System.Diagnostics.Debug.Print("OfficeHelper::Cleanup - GC forced");
    GC.Collect();
    GC.WaitForPendingFinalizers();
    System.Diagnostics.Debug.Print("OfficeHelper::Cleanup - GC finished");
  }

}

So far this approach has worked well in my app, and the GC times have been faster than I expected.

Upvotes: 1

Related Questions