Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 其中';这个函数中的内存泄漏是什么?_C#_.net_Memory Leaks_Io - Fatal编程技术网

C# 其中';这个函数中的内存泄漏是什么?

C# 其中';这个函数中的内存泄漏是什么?,c#,.net,memory-leaks,io,C#,.net,Memory Leaks,Io,Edit2:我只想确定我的问题是清楚的:为什么在AppendToLog()的每次迭代中,应用程序都会多使用15mb?(原始日志文件的大小) 我有一个名为AppendToLog()的函数,它接收HTML文档的文件路径,进行一些解析并将其附加到文件中。它被称为: this.user_email = uemail; string wanted_user = wemail; string[] logPaths; logPaths = this.getLogPaths(wanted_user); fo

Edit2:我只想确定我的问题是清楚的:为什么在AppendToLog()的每次迭代中,应用程序都会多使用15mb?(原始日志文件的大小)

我有一个名为AppendToLog()的函数,它接收HTML文档的文件路径,进行一些解析并将其附加到文件中。它被称为:

this.user_email = uemail;
string wanted_user = wemail;

string[] logPaths;
logPaths = this.getLogPaths(wanted_user);

foreach (string path in logPaths)
{              

    this.AppendToLog(path);                

}
在每次迭代中,RAM的使用量都会增加15mb左右。这是函数:(看起来很长,但很简单)

这件事我已经谈了好几天了,我不知道该怎么办:(

编辑:这是ParseMessages,一个使用HtmlAlityPack剥离HTML日志部分的函数

public string[] parseMessages(string what)
{
StringBuilder sb = new StringBuilder();
HtmlDocument doc = new HtmlDocument();

doc.LoadHtml(what);            

HtmlNodeCollection messageGroups = doc.DocumentNode.SelectNodes("//body/div[@class='mplsession']");
int messageCount = doc.DocumentNode.SelectNodes("//tbody/tr").Count;

doc = null;

string[] buffer = new string[messageCount];

int i = 0;

foreach (HtmlNode sessiongroup in messageGroups)
{
    HtmlNode tablegroup = sessiongroup.SelectSingleNode("table/tbody");

    string sessiontime = sessiongroup.Attributes["id"].Value;

    HtmlNodeCollection messages = tablegroup.SelectNodes("tr");
    if (messages != null)
    {
        foreach (HtmlNode htmlNode in messages)
        {
            sb.Append(
                    ParseMessageDate(
                        sessiontime,
                        htmlNode.ChildNodes[0].ChildNodes[0].InnerText
                    )
                ); //Date
            sb.Append(" ");

            try
            {
                foreach (HtmlTextNode node in htmlNode.ChildNodes[0].SelectNodes("text()"))
                {
                    sb.Append(node.Text.Trim()); //Name
                }
            }
            catch (NullReferenceException)
            {
                /*
                 * We ignore this exception, it just means there's extra text
                 * and that means that it's not a normal message
                 * but a system message instead
                 * (i.e. "John logged off")
                 * Therefore we add the "::" mark for future organizing
                 */
                sb.Append("::");
            }
            sb.Append(" ");

            string message = htmlNode.ChildNodes[1].InnerHtml;
            message = message.Replace(""", "'");
            message = message.Replace(" ", " ");
            message = RemoveMedia(message);
            sb.Append(message); //Message
            buffer[i] = sb.ToString();
            sb = new StringBuilder();
            i++;
        }
    }
}
messageGroups = null;
what = null;
return buffer;
}

您可能想尝试的一件事是,在每次运行后临时强制执行GC.Collect。GC非常智能,并且不会回收内存,直到is认为收集的费用相当于任何已恢复内存的价值


编辑:我只是想补充一点,重要的是要理解手动调用GC.Collect是一种不好的做法(对于任何正常的用例来说,异常==可能是游戏或类似游戏的加载函数)。您应该让垃圾回收器决定什么是最好的,因为它通常会有比您所能获得的更多的关于系统资源等信息来作为其收集行为的基础。

在将消息数组和stringbuilder设置为null之前,我会手动清除它们

编辑

看看这个过程似乎在做什么,我得到了一个建议,如果还不算太晚的话,那就不要解析html文件


创建一个数据集架构,并使用它来写入和读取xml日志文件,并使用xsl文件将其转换为html文件。

try-catch块可以使用finally(清理)。如果您看一下using语句的作用,它相当于try catch finally。是的,运行GC也是一个好主意。如果不编译此代码并尝试一下,很难确定

此外,使用以下工具妥善处置这名男子:

FileStream destf=新文件流(destFileName,FileMode.Append)


查找有效的C#2nd edition

我会仔细研究为什么需要向parseMessages传递字符串,即fb.ToString()


您的代码注释表示,这将返回每行内容的数组。但是,实际上您正在将日志文件中的所有行读取到fb中,然后转换为字符串

如果要在parseMessages()中解析大文件,可以通过将StringBuilder本身或StreamReader传递到parseMessages()中来更高效地完成此操作。这将允许在任何时候只将文件的一部分加载到内存中,而不是使用ToString()将整个日志文件强制加载到内存中

由于垃圾收集,您在.NET应用程序中不太可能出现真正的内存泄漏。您看起来并没有使用任何大型资源(如文件),因此出现实际内存泄漏的可能性似乎更小

看起来您已经处理了资源,但是GC可能正在努力分配大内存块,然后在下一次迭代开始之前及时取消分配,因此您会看到内存使用率的增加

虽然GC.Collect()可能允许您强制释放内存,但我强烈建议您在尝试通过GC手动管理内存之前,先查看上面的建议

[更新]看到您的parseMessages()和HtmlAgilityPack(顺便说一句,这是一个非常有用的库)的使用,似乎每个逻辑都会执行一些大的、可能是大量的内存分配

Htmlagibility在内部为各种节点分配内存,当与您的缓冲区数组和主函数中的分配相结合时,我更确信GC将承受巨大的压力以跟上

为了停止猜测并获得一些真实的指标,我将运行并添加列以显示GC Gen 0,1,2 collections列。然后运行应用程序并观察集合的数量。如果在这些列中看到大量的集合,那么GC将陷入困境,您应该重新设计以使用更少的内存分配


或者,免费的Microsoft提供了应用程序中.NET内存分配的良好可视化表示。

我没有看到任何明显的内存泄漏;我的第一个猜测是它在库中

一个解决这类问题的好工具是SciTech的.NET内存分析器。他们有两周的免费试用期

除此之外,您可以尝试注释一些库函数,看看如果您只读取文件而不处理数据,问题是否会消失


另外,您在哪里查找内存使用统计数据?请记住,任务管理器报告的统计数据并不总是非常有用或反映实际内存使用情况。

正如许多人提到的,这可能只是GC的一个工件,没有像您期望的那样快速清理内存存储。这对于托管语言来说是正常的s、 如C#、Java等。如果您对该用法感兴趣,您确实需要了解分配给程序的内存是否可用。与此相关的问题有:

  • 您的程序运行多长时间?它是连续运行的服务类型程序吗
  • 在整个执行过程中,它是继续从操作系统分配内存,还是达到了稳定状态?(您是否运行了足够长的时间来发现?)
  • 您的代码看起来不会出现“内存泄漏”。在托管语言中,您确实不会像在C/C++中那样出现内存泄漏(除非您使用的是不安全的或是C/C++的外部库)。但发生的情况是,您确实需要注意保留或隐藏的引用(就像一个集合类,它被告知删除一个项,但没有将内部数组的元素设置为
    nullpublic string[] parseMessages(string what)
    {
    StringBuilder sb = new StringBuilder();
    HtmlDocument doc = new HtmlDocument();
    
    doc.LoadHtml(what);            
    
    HtmlNodeCollection messageGroups = doc.DocumentNode.SelectNodes("//body/div[@class='mplsession']");
    int messageCount = doc.DocumentNode.SelectNodes("//tbody/tr").Count;
    
    doc = null;
    
    string[] buffer = new string[messageCount];
    
    int i = 0;
    
    foreach (HtmlNode sessiongroup in messageGroups)
    {
        HtmlNode tablegroup = sessiongroup.SelectSingleNode("table/tbody");
    
        string sessiontime = sessiongroup.Attributes["id"].Value;
    
        HtmlNodeCollection messages = tablegroup.SelectNodes("tr");
        if (messages != null)
        {
            foreach (HtmlNode htmlNode in messages)
            {
                sb.Append(
                        ParseMessageDate(
                            sessiontime,
                            htmlNode.ChildNodes[0].ChildNodes[0].InnerText
                        )
                    ); //Date
                sb.Append(" ");
    
                try
                {
                    foreach (HtmlTextNode node in htmlNode.ChildNodes[0].SelectNodes("text()"))
                    {
                        sb.Append(node.Text.Trim()); //Name
                    }
                }
                catch (NullReferenceException)
                {
                    /*
                     * We ignore this exception, it just means there's extra text
                     * and that means that it's not a normal message
                     * but a system message instead
                     * (i.e. "John logged off")
                     * Therefore we add the "::" mark for future organizing
                     */
                    sb.Append("::");
                }
                sb.Append(" ");
    
                string message = htmlNode.ChildNodes[1].InnerHtml;
                message = message.Replace(""", "'");
                message = message.Replace(" ", " ");
                message = RemoveMedia(message);
                sb.Append(message); //Message
                buffer[i] = sb.ToString();
                sb = new StringBuilder();
                i++;
            }
        }
    }
    messageGroups = null;
    what = null;
    return buffer;
    }
    
    FileInfo fi = new FileInfo(path);
    StringBuilder fb = new StringBuilder((int) fi.Length);
    
    if (node.Text != null)
        sb.Append(node.Text.Trim()); //Name