After this we researched a bit to see as to what is really causing the Excel process to live in memory forever. And to answer this and several other basic questions, I wrote a small windows console application as my POC. Below is how the source appears.
using System;In above code, I am creating a new excel application, adding new workbook in it and then releasing both application and workbook references (observe that we explicitly created only two interop references xlApp and newWorkbook).
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;
using System.Runtime.InteropServices;
namespace GhostXLInstance
{
class Program
{
static void Main(string[] args)
{
Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
Excel.Workbook newWorkbook = xlApp.Workbooks.Add(Missing.Value);
int workbookRCWCounter = Marshal.ReleaseComObject(newWorkbook);
Console.WriteLine("RCW counter for workbook :: " + workbookRCWCounter.ToString());
xlApp.Quit();
int excelRCWCounter = Marshal.ReleaseComObject(xlApp);
Console.WriteLine("RCW counter for XL application :: " + excelRCWCounter.ToString());
Console.Read();
}
}
}
After executing the example, you will see two lines in console telling you the RCW count for each object we released. Viola!!! It is zero which apparently means that all the objects we referenced are released. However, if you observe the task manager now the excel instance is still running. So the question still remains the same – What is holding the excel process?
Well, then I got a fantastic article http://blogs.msdn.com/geoffda/archive/2007/08/31/the-designer-process-that-would-not-terminate.aspx which explained the phenomena. So here is the phenomenon in simple words.
If you closely observe our example, we are actually getting three references. The third reference is implicitly created when we used the application’s Workbooks collection to add new workbook.
Excel.Workbook newWorkbook = xlApp.Workbooks.Add(Missing.Value);Observe that xlApp.Workbooks actually returns Microsoft.Office.Interop.Excel.Workbooks reference. Wow! So did we got the cause of immutability of excel process? Yes! So this uninvited third reference lives forever in the memory and causes the excel process to wait for its garbage collection.
Now since we got the cause, lets modify our previous code to release third reference even.
using System;Finally in modified code, I am collecting the xlApp.Workbooks reference to a local variable and then releasing it. And now executing this code would release the ghost application while console application is waiting at Console.Read();
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;
using System.Runtime.InteropServices;
namespace GhostXLInstance
{
class Program
{
static void Main(string[] args)
{
Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
Excel.Workbooks workbooks = xlApp.Workbooks;
Excel.Workbook newWorkbook = workbooks.Add(Missing.Value);
int workbookRCWCounter = Marshal.ReleaseComObject(newWorkbook);
Console.WriteLine("RCW counter for workbook :: " + workbookRCWCounter.ToString());
int workbooksRCWCounter = Marshal.ReleaseComObject(workbooks);
Console.WriteLine("RCW counter for workbooks :: " + workbooksRCWCounter.ToString());
xlApp.Quit();
int excelRCWCounter = Marshal.ReleaseComObject(xlApp);
Console.WriteLine("RCW counter for XL application :: " + excelRCWCounter.ToString());
Console.Read();
}
}
}
Conclusion:
Well so from our POC it became apparent that the so called collection references (like workbooks, shapes, charts …) needs to be explicitly referenced in local variable and garbage collected to neatly exit excel process.
Note: In my next posting I will detail the right way to release Interop references.
No comments:
Post a Comment