Outlook 2007 加载项内存泄漏?

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();
        }            

热补丁解决了你的问题吗?也许你需要释放每个单独的附件(请参见我的更新)? - Dirk Vollmar
4个回答

2
您是否在使用“foreach”循环处理附件(在代码片段中没有显示)?
根据一篇博客文章,“foreach”会导致内存泄漏,而“for”则不会:
引用: OOM.NET: Part 2 - Outlook Item Leaks 显然也有一个热修复程序,解决了有关内存泄漏的各种问题。
更新
您是否尝试释放包含在附件集合中的每个单独的附件?
for (int i = 1; i <= oAttachs.Count; i++)
{
    Outlook.Attachment oAttach = oAttachs[i];

    // Do nothing with attachment
    Marshal.ReleaseCOMObject(oAttach);
    oAttach = null;
}

今天早上我在使用foreach,但是我之前看到了那篇OOM.NET文章,于是把代码改成了你现在看到的for循环,但并没有什么效果。我现在开始研究一下你发布的hotfix... - NickL
所以for和foreach不是问题的原因。无论如何,OOM似乎有点棘手。您是否尝试按照您发布的代码运行它(即没有留下“//在此执行一些实际工作”部分)?那样是否仍然存在内存泄漏?否则,问题将出现在代码的特定部分(无论如何,我会尝试注释掉代码的某些部分,直到内存泄漏消失;调试器可能无法显示代码中的正确位置)。 - Dirk Vollmar
是的,我发布的代码就是我正在运行的。我已经实现了“实际工作”代码,但暂时将其注释掉了。罪魁祸首肯定是我第一次访问Msg.Attachments的那行代码(无论是像我的示例中一样分配给一个新对象,还是简单地条件检查,比如Msg.Attachments.Count)。没有那行代码,我就没有问题(但当然也无法访问附件)。 - NickL
截至今天早上,热修补似乎没有起到任何作用。我还尝试了逐个发布每个附件 - 不幸的是,这也没有解决问题。感谢您迄今为止对此事的帮助;我仍在调查此问题,如果我发现解决方案,我会再次发布。 - NickL

0

如果没有其他问题,我会先检查 Msg 对象是否有附件,然后再调用这行代码:

 Outlook.Attachments objAttachments = Msg.Attachments;

否则,您将为每个消息分配内存,而不管是否存在附件...因此,如果只有5,000个带附件的消息,则应该仅执行5,000次,而不是所有的~25,000次。

这样的条件语句,比如 'if(Msg.Attachments.Count > 0) { }',也会导致分配相同数量的内存。 - NickL

0

你有没有尝试检查Marshal.ReleaseComObject()是否总是返回0,也许你在其他地方有额外的引用?

此外,你有没有找到任何Dispose项。然后你应该调用Dispose()


我刚刚调查了这个建议 - 我对 Marshal.ReleaseComObject() 的调用总是返回 <= 0,我认为这应该没问题。 - NickL

0

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

  1. 将objSelectedItems中的每个对象复制到本地声明的List中。
  2. 调用Marshal.ReleaseComObject(objSelectedItems)。
  3. 按照上述问题所述进行我的循环 - 但修改为使用本地对象列表而不是Outlook选择。

显然,这意味着出于某种原因,必须在释放Selection之前释放其中的各个对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接