【问题标题】:Worksheet.Name causes OutOfMemoryExceptionWorksheet.Name 导致 OutOfMemoryException
【发布时间】:2012-05-30 12:49:32
【问题描述】:

.Net4 C# VSTO4 Excel 插件:

下面的函数被调用的频率很高,比如说每秒:

   /// <summary>
    /// Gets a unique identifier string of for  the worksheet in the format [WorkbookName]WorksheetName
    /// </summary>
    /// <param name="workbook">The workbook.</param>
    /// <param name="worksheet">The worksheet.</param>
    /// <returns>
    /// A unique worksheet identifier string, or an empty string.
    /// </returns>
    public static string GetWorksheetUniqueIdentifier(Workbook workbook, dynamic worksheet)
    {
        if (workbook == null) return string.Empty;
        if (worksheet == null) return string.Empty;//Note: Worksheet can also be a diagram!

        return string.Format("[{0}]{1}", workbook.Name, worksheet.Name);
    }

一段时间后,我收到以下异常:

System.OutOfMemoryException
   at System.Collections.Generic.Dictionary`2.Resize()
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at Microsoft.CSharp.RuntimeBinder.Semantics.SYMTBL.InsertChildNoGrow(Symbol child)
   at Microsoft.CSharp.RuntimeBinder.Semantics.SymFactoryBase.newBasicSym(SYMKIND kind, Name name, ParentSymbol parent)
   at Microsoft.CSharp.RuntimeBinder.Semantics.SymFactory.CreateLocalVar(Name name, ParentSymbol parent, CType type)
   at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.PopulateLocalScope(DynamicMetaObjectBinder payload, Scope pScope, ArgumentObject[] arguments, IEnumerable`1 parameterExpressions, Dictionary`2 dictionary)
   at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindCore(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding)
   at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.Bind(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding)
   at Microsoft.CSharp.RuntimeBinder.BinderHelper.Bind(DynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable`1 args, IEnumerable`1 arginfos, DynamicMetaObject onBindingError)
   at Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder.FallbackInvokeMember(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
   at System.Dynamic.DynamicMetaObject.BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
   at System.Dynamic.InvokeMemberBinder.Bind(DynamicMetaObject target, DynamicMetaObject[] args)
   at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
   at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T](CallSite`1 site, Object[] args)
   at System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2)
   at CallSite.Target(Closure , CallSite , Object , Object )
   at TestAddIn.ExcelAccessor.GetWorksheetUniqueIdentifier(Workbook workbook, Object worksheet)
   at TestAddIn.ExcelAccessor.GetCurrentWorksheetUniqueIdentifier()
   at TestAddIn.ExcelAccessor.timerExcelObserver_Tick(Object sender, EventArgs e)--------------------------------------------------------------------------------------------------------

调用代码是:

  private static Timer timerExcelObserver = new Timer();

...

  timerExcelObserver.Tick += new EventHandler(this.timerExcelObserver_Tick);
  timerExcelObserver.Interval = 1000;
  timerExcelObserver.Start();

...

  private void timerExcelObserver_Tick(object sender, EventArgs e)
  { 
    ...
    var updatedWorksheetIdentifierString = GetCurrentWorksheetUniqueIdentifier();
    ...
  }

  public static string GetCurrentWorksheetUniqueIdentifier()
  {
      return GetWorksheetUniqueIdentifier(ExcelApplication.ActiveWorkbook, ExcelApplication.ActiveSheet);
  }

我不知道为什么会出现异常!

在 GetWorksheetUniqueIdentifier 中“使用”可能会有所帮助吗?

using(worksheet)
{
   return string.Format("[{0}]{1}", workbook.Name, worksheet.Name);
}

有人有答案吗?

【问题讨论】:

  • 在某些字典中插入时好像出了点问题,你能分享完整的堆栈跟踪吗
  • 这段代码从哪里调用或如何使用?它似乎不是问题的直接原因(在 Dictionary resize 方法中死机),因此调用代码可能有问题。
  • 不要释放 worksheet 对象,如果您使用您发布的 using 语句会发生这种情况。在您的方法完成后,调用者可能仍需要引用 worksheet
  • @Keith:我认为离开 using() 子句时不会释放工作表对象,因为在函数之外还有其他一些对它的引用。
  • 你为什么使用dynamic而不是Excel.Worksheet

标签: c# excel vsto add-in out-of-memory


【解决方案1】:

尝试显式释放 COM 对象:

public static string GetCurrentWorksheetUniqueIdentifier()
{
    var workbook = ExcelApplication.ActiveWorkbook;
    var worksheet = ExcelApplication.ActiveSheet;

    try
    {
        return GetWorksheetUniqueIdentifier(workbook, worksheet);
    }
    finally
    {
        if (workbook != null &&
            Marshal.IsComObject(workbook))
            Marshal.ReleaseComObject(workbook);

        if (worksheet != null && 
            Marshal.IsComObject(worksheet))
            Marshal.ReleaseComObject(worksheet);
    }
}

已知这可以修复某些与 Office 相关的场景中的内存问题。

【讨论】:

  • 我不知道这是否真的解决了问题,因为我无法重现它。但这是迄今为止最好的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-14
  • 1970-01-01
  • 2016-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多