耗尽内存循环遍历邮件项目 [英] Running out of memory looping through mail items

查看:63
本文介绍了耗尽内存循环遍历邮件项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Outlook com插件,正在为我做一些简单的搜索技巧.我正在将其组合在一起,但是我遇到了内存不足的问题.该过程非常简单,基本上遍历了Outlook文件夹,检查每个mailItem是否匹配.给定循环,每次我希望垃圾收集器继续运行时都要重新初始化变量,但是当我观察内存时,它以每秒10m的速度丢失,直到系统内存不足并且出现未处理的异常.

Hi I have a Outlook com addin that is doing some simple searching tricks for me. I am part way through putting it together but I am having issues with it running out of memory. The process is very simple and basically loops through an outlook folder checking each mailItem for a match. given the loop reinitialize the variables each time I would have expected the garbage collector to keep up but when I watch the memory it loses ~10m/sec until the system is out of memory and I get unhandled exceptions.

这是代码的一部分

private void FindInFolder(Outlook.MAPIFolder FolderToSearch)
    {
        Outlook.MailItem mailItem;
        Outlook.MAPIFolder ParentFolder;

        int counter = 0;

        StatusBar.Text = "Searching in Folder " + FolderToSearch.FolderPath + "/" + FolderToSearch.Name;
        StatusBar.Update();
        this.Update();

        foreach (COMObject item in FolderToSearch.Items)
        {
            counter++;
            if (counter % 100 == 0)
            {
                StatusBar.Text = FolderToSearch.FolderPath + "/" + FolderToSearch.Name + " item " + counter + " of " + FolderToSearch.Items.Count;
                StatusBar.Update();
                if (counter % 1000 == 0)
                {
                    GC.Collect();
                }
            }
            if (item is Outlook.MailItem)
            {
                mailItem = item as Outlook.MailItem;
                if (IsMatch(mailItem))
                {
                    if (mailItem.Parent is Outlook.MAPIFolder)
                    {
                            ParentFolder = mailItem.Parent as Outlook.MAPIFolder;
                            ResultGrd.Rows.Add(mailItem.EntryID, ParentFolder.FolderPath, mailItem.SenderName, mailItem.Subject, mailItem.SentOn);
                    }
                }
            }
            mailItem = null;
        }
    }

哪个电话

        private Boolean IsMatch(Outlook.MailItem inItem)
    {
        Boolean subBool = false;
        Boolean NameBool = false;

        try
        {
            if (null != inItem)
            {
                if (SubjectTxt.Text != "")
                {
                    if (inItem.Subject.Contains(SubjectTxt.Text))
                    {
                        subBool = true;
                    }
                }
                else
                {
                    subBool = true;                    
                }

                if (NameTxt.Text != "")
                {
                    if (inItem.Sender != null)
                    {
                        if (inItem.Sender.Name.Contains(NameTxt.Text))
                        {
                            NameBool = true;
                        }
                    }
                }
                else 
                {
                    NameBool = true;
                }

                return subBool && NameBool;

            }
        }
        catch (System.Runtime.InteropServices.COMException ce)
        {
            if (ce.ErrorCode == -2147467259)
            {
                //DO nothing just move to the next one
            }
            else
            {
                MessageBox.Show("Crash in IsMatch error code = " + ce.ErrorCode + " " + ce.InnerException);
            }
        }
        return false;
    }

请原谅底部的所有错误捕获部分和GC.收集它们是我找出错误和释放内存的一些尝试.

Please excuse all the error catching part at the bottom and the GC.collect they are some of my attempts to work out what is wrong and free up memory.

还请注意,FindInFolder由新线程调用,因此我可以在继续搜索的同时与结果进行交互.

Note also FindInFolder is called by a new thread so I can interact with results while it continues to search.

到目前为止我尝试过的事情:

What I have tried so far:

使函数的局部变量不是类,因此G可以检索它们,但是,"item"中最常用的变量是foreach的一部分,因此必须以这种方式声明.

Making variables local to function not class so the are retrievable by G, however the most used variable in 'item' as it is part of foreach it must be declared that way.

每1000个mailItem都进行一次手动GC,这完全没有区别.

every 1000 mailItems do a manual GC, this made no difference at all.

由于某种原因,它只需要遍历所有项就需要大量内存,而GC永远不会释放它们.

For some reason it needs alot of memory just looping through the items and GC never frees them up.

还请注意,我使用netoffice而不是VSTO作为Com插件.

Please also note I am using netoffice not VSTO for Com addin.

推荐答案

首先:这是NetOffice代码,您在NetOffice中不需要Marshal.ReleaseComObject.(此外,在这里调用ReleaseComObject没用)将Dispose()用作实例.

First of it all: This is NetOffice code and you dont need Marshal.ReleaseComObject in NetOffice. (Moreover, its useless to call ReleaseComObject here) Use Dispose() for the instance instead.

请记住:NetOffice为您处理COM代理(这就是为什么它允许在NetOffice中使用两个2点).在您的情况下,其内部存储为://FolderToSearch- 项目-枚举器- 物品- 物品-....

Keep in your mind: NetOffice handle COM proxies for you (Thats why its allowed to use two 2 dots in NetOffice). In your case its internaly stored as: // FolderToSearch -- Items --Enumerator -- Item -- Item -- ....

在每个循环的末尾使用item.Dispose()来删除/释放item实例,或者在foreach之后使用以下内容

Use item.Dispose() at the end of each loop to remove/free the item instance or use the following after foreach

FolderToSearch.Dipose()//处置文件夹实例,那里的所有代理都来自

FolderToSearch.Dipose() // dispose folder instance and all proxies there comes from

FolderToSearch.DisposeChildInstances()//处理所有来自其中的代理,但保持文件夹实例处于活动状态

FolderToSearch.DisposeChildInstances() // dispose all proxies there comes from but keep the folder instance alive

下一个:此处的项目枚举器是一个自定义枚举器(由NetOffice提供)但是,它适用于少量物品,但不要在更多物品中使用较重的情况(可能交换服务器和数千个项目).本地工作站/程序无法在内存中处理此问题.因此,Microsoft仅提供众所周知的GetFirst/GetNext模式.在NetOffice中,它看起来像:

Next: The Items enumerator here is a custom enumerator(given by NetOffice) However it works fine with small amount of items but dont do this in a more heavier scenario(may exchange server and thousands of items). The local workstation/program can't handle this in memory. For this reason Microsoft provides only the well kown GetFirst/GetNext pattern. In NetOffice it looks like:

Outlook._Items items = FolderToSearch.Items;
COMObject item = null;
do
{
    if (null == item)
       item = items.GetFirst() as COMObject;
    if (null == item)
       break;

    // do what you want here

    item.Dispose();
    item = items.GetNext() as COMObject;
} while (null != item);

这应该也可以.

这篇关于耗尽内存循环遍历邮件项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆