8 Stimmen

Wo ist das Speicherleck in dieser Funktion?

Bearbeiten2: Ich möchte nur sicherstellen, dass meine Frage klar ist: Warum, bei jeder Iteration von AppendToLog(), die Anwendung 15mb mehr verwendet? (die Größe der ursprünglichen Protokolldatei)

Ich habe eine Funktion namens AppendToLog(), die den Dateipfad eines HTML-Dokuments empfängt, etwas analysiert und an eine Datei anhängt. Sie wird auf diese Weise aufgerufen:

this.user_email = uemail;
string wanted_user = wemail;

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

foreach (string path in logPaths)
{              

    this.AppendToLog(path);                

}

Bei jeder Iteration steigt der RAM-Verbrauch um etwa 15 MB. Dies ist die Funktion: (sieht lang aus, ist aber einfach)

public void AppendToLog(string path)
{

Encoding enc = Encoding.GetEncoding("ISO-8859-2");
StringBuilder fb = new StringBuilder();
FileStream sourcef;
string[] messages;

try
{
    sourcef = new FileStream(path, FileMode.Open);
}
catch (IOException)
{
    throw new IOException("The chat log is in use by another process."); ;
}
using (StreamReader sreader = new StreamReader(sourcef, enc))
{

    string file_buffer;
    while ((file_buffer = sreader.ReadLine()) != null)
    {
        fb.Append(file_buffer);
    }                
}

//Array of each line's content
messages = parseMessages(fb.ToString());

fb = null;

string destFileName = String.Format("{0}_log.txt",System.IO.Path.GetFileNameWithoutExtension(path));
FileStream destf = new FileStream(destFileName, FileMode.Append);
using (StreamWriter swriter = new StreamWriter(destf, enc))
{
    foreach (string message in messages)
    {
        if (message != null)
        {
            swriter.WriteLine(message);
        }
    }
}

messages = null;

sourcef.Dispose();
destf.Dispose();

sourcef = null;
destf = null;
}

Ich habe seit Tagen damit zu tun und weiß nicht, was ich tun soll :(

Bearbeiten: Dies ist ParseMessages, eine Funktion, die HtmlAgilityPack verwendet, um Teile eines HTML-Protokolls zu entfernen.

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

0 Stimmen

Sie brauchen keine FileStream wenn Sie eventuell eine StreamReader . Sehen Sie sich die Konstrukteure an.

0voto

Fredou Punkte 19430

Ich würde das Array der Nachricht und den Stringbuilder manuell löschen, bevor ich sie auf null setze.

bearbeiten

Wenn ich mir anschaue, was der Prozess zu tun scheint, habe ich einen Vorschlag, wenn es nicht zu spät ist, anstatt eine html-Datei zu analysieren.

ein Datenschema erstellen und dieses zum Schreiben und Lesen einer XML-Protokolldatei und zur Umwandlung in eine HTML-Datei mit einer XSL-Datei verwenden.

0voto

RickNZ Punkte 18158

Ich sehe keine offensichtlichen Speicherlecks; meine erste Vermutung wäre, dass es etwas in der Bibliothek ist.

Ein gutes Tool, um diese Art von Dingen herauszufinden, ist der .NET Memory Profiler von SciTech. Sie bieten eine kostenlose zweiwöchige Testversion an.

Ansonsten könnten Sie versuchen, einige der Bibliotheksfunktionen auszukommentieren und zu sehen, ob das Problem verschwindet, wenn Sie die Dateien nur lesen und nichts mit den Daten machen.

Und wo suchen Sie nach Statistiken über die Speichernutzung? Denken Sie daran, dass die vom Task-Manager gemeldeten Statistiken nicht immer sehr nützlich sind oder den tatsächlichen Speicherverbrauch widerspiegeln.

0voto

KVK Punkte 1

HtmlDocument-Klasse (soweit ich feststellen kann) hat eine ernsthafte Speicherleck, wenn von verwaltetem Code verwendet. Ich reccomend mit dem XMLDOM-Parser stattdessen (obwohl dies erfordert gut geformte Dokumente, aber das ist ein anderes +).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X