2

我下载了所有邮件并检查了它们的附件。他们正在填充 RAM。我在线程中被称为该代码。我尝试使用 client.Dispose() 和 GC.Collect() 但没有帮助:(( 在此处输入图像描述

using (var client = new ImapClient(hostname, true))
{
    if (client.Connect( /* optional, use parameters here */ ))
    {
        // connection successful
        if (client.Login(login, pass))
        {
            // login successful
            FolderCollection folders = client.Folders;
            int i = 0;
            foreach (Folder myfolder in folders)
            {

                var messages = client.Folders[i].Search("ALL");
                i++;
                foreach (var message in messages)
                {
                    var attachments = message.Attachments;
                    if (attachments.Count() > 0)
                        if (!Directory.Exists(folder + @"\" + login))
                        {
                            DirectoryInfo di = Directory.CreateDirectory(folder + @"\" + login);// Try to create the directory.
                        }
                    foreach (var attachment in attachments)
                    {
                        attachment.Download();
                        attachment.Save(folder + @"\" + login);
                    }
                }

                GC.Collect();
            }
        }
    }
    client.Disconnect();
    client.Dispose();
}
4

2 回答 2

2

首先,GC.Collect();Message对象在当前范围内仍然存在时,您正在调用。

您正在调用client.Dispose();using语句的另一个问题实际上是相同的,因为它只是下一个代码的语法糖:

var client = new ImapClient(hostname, true)
try
{
    ...
}
finally
{
    if (client != null)
    {
        ((IDisposable)client).Dispose();
    }
}

您的示例没有内存泄漏,GC 将在 next 上自动收集Message对象。Collect()

如果你想强制垃圾收集,你可以GC.Collect()using块后调用,但这真的是蝙蝠练习。可以通过调用 Collect 来强制进行垃圾回收,但大多数情况下应该避免这样做,因为它可能会产生性能问题。

如果确实需要在循环内收集对象,请尝试使用GCSettings.LargeObjectHeapCompactionMode属性或WaitForPendingFinalizers()方法。完整的代码将如下所示:

foreach (Folder myfolder in folders)
{

    var messages = client.Folders[i].Search("ALL");
    i++;
    foreach (var message in messages)
    {
        var attachments = message.Attachments;
        if (attachments.Count() > 0)
            if (!Directory.Exists(folder + @"\" + login))
            {
                DirectoryInfo di = Directory.CreateDirectory(folder + @"\" + login);// Try to create the directory.
            }
        foreach (var attachment in attachments)
        {
            attachment.Download();
            attachment.Save(folder + @"\" + login);
        }
        attachments = null;
    }

    messages = null;

    // performance killer
    GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
    GC.Collect(2);
    GC.WaitForPendingFinalizers();
    GC.Collect(2); 
} 

请注意,它不是生产代码,而是针对您的问题的组合解决方法。

于 2016-01-26T10:02:57.347 回答
0

GC.Collect()在您明确知道自己在做什么之前,您永远不应该打电话。这也无济于事,因为当您的程序占用大量 RAM 时,CLR 会自行运行 GC。如果您看到内存消耗正在增长,那么您似乎有非托管资源泄漏。

我根据 ImapX 项目编辑了我的代码:几乎没有需要手动处置的资源。所以这里唯一能做的就是路径的实习。您还应该实习登录名和密码,因为您的代码不会创建其他字符串。经过几项改进后,将如下所示:

public void DownloadAllAttachments()
{
    using (var client = new ImapClient(hostname, true))
    {
        if (!client.Connect( /* optional, use parameters here */) || !client.Login(login, pass))
            return;

        string path = string.Intern(Path.Combine(folder, login));
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }

        foreach (Folder myfolder in client.Folders)
        {
            foreach (var message in myfolder.Search())
            {
                foreach (var attachment in message.Attachments)
                {
                    attachment.Download();
                    attachment.Save(path);
                }
            }
        }
    }
}
于 2016-01-26T12:35:28.343 回答