3

我使用 C# 创建了一个简单的 Outlook 2007 加载项,该加载项循环选择消息并检查其附件。

我在一组约 25,000 条选定的消息上运行此加载项。然而,我立即注意到 Outlook 的内存使用量(通过 perfmon 看到)猛增。在调试模式下逐行运行加载项后,很明显,在第一次访问邮件的附件集合时,内存已分配给 Outlook。该内存永远不会返回给系统;Outlook 继续消耗内存,直到达到约 1GB(大约 12,000 条消息后),然后我收到“内存或系统资源不足”错误。有任何想法吗?

以下是部分代码:

        for(int i = 1; i <= objSelectedItems.Count; i++)
        {
            Object objMsg = objSelectedItems[i];

            //Only process if Item is a Message
            if (objMsg is Outlook.MailItem)
            {
                Outlook.MailItem Msg = objMsg as Outlook.MailItem;

                //The culprit: this allocates memory to Outlook which I can't get back
                Outlook.Attachments objAttachments = Msg.Attachments;

                //Perform some actual work here//

                //Clean up Outlook objects; does not appear to give memory back to system
                Msg.Close(Microsoft.Office.Interop.Outlook.OlInspectorClose.olDiscard);
                Marshal.ReleaseComObject(objAttachments);
                Marshal.ReleaseComObject(Msg);
            }

            Marshal.ReleaseComObject(objMsg);
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }            
4

4 回答 4

2

您是否使用foreach循环来处理附件(该部分在您的代码片段中被遗漏)?

根据一篇博客文章foreach会导致内存泄漏,而for不会:

OOM.NET:第 2 部分 - Outlook 项目泄漏

显然,还有一个修补程序可用于修复有关内存泄漏的各种问题。

更新

您是否尝试过释放附件集合中包含的每个附件?

for (int i = 1; i <= oAttachs.Count; i++)
{
    Outlook.Attachment oAttach = oAttachs[i];

    // Do nothing with attachment
    Marshal.ReleaseCOMObject(oAttach);
    oAttach = null;
}
于 2009-10-15T16:12:00.157 回答
0

如果没有别的,我会在调用此行之前先检查 Msg 对象的附件:

 Outlook.Attachments objAttachments = Msg.Attachments;

否则,无论是否存在附件,您都会为每条消息分配...所以如果只有 5,000 条带有附件的消息,则应该只执行 5,000 次而不是全部 ~25,000 次

于 2009-10-15T16:11:38.547 回答
0

您是否尝试检查 Marshal.ReleaseComObject() 是否始终返回 0,也许您在某处有其他引用?

此外,您是否找到任何 Dispose 项目。然后你应该调用 Dispose()

于 2009-10-15T16:13:10.077 回答
0

我似乎已经解决了这个问题。由于 objSelectedItems 是通过 Applicaiton.ActiveExplorer().Selection 引入的,因此我执行了以下操作:

  1. 将 objSelectedItems 中的每个 Object 复制到本地声明的 List 中。
  2. 调用 Marshal.ReleaseComObject(objSelectedItems)。
  3. 开始我在上面问题中发布的循环 - 尽管修改为使用本地对象列表而不是 Outlook 选择。

这显然意味着,出于某种原因,必须先释放选择,然后才能释放其中的各个对象。

于 2009-10-16T15:38:34.577 回答