归档日志文件时出现内存不足错误

Out of memory error archiving a log file

我在运行并创建我在午夜存档的每日日志文件的控制台作业时遇到问题。

这会为第二天创建一个空白日志文件,并在名称和旧文件内容中创建一个包含昨天日期的存档文件,用于调试我可能已经遇到但直到第二天才知道的问题。

然而,自从我启动 BOT 的工作后,我在尝试存档文件时遇到了系统内存不足错误的问题。

起初我根本无法获得存档文件,然后我找到了一种方法来至少获得最后 100,000 行,这还远远不够。

我把所有东西都包在 3 个里 try/catches

  1. I/O
  2. 系统内存不足
  3. 标准例外

然而,我得到的总是 OutOfMemoryException,例如

System.OutOfMemoryException 错误:抛出 'System.OutOfMemoryException' 类型的异常。;

给你举个例子,100,000行的日志大约是11MB的文件

一个标准的完整日志文件可以是 1/2 GB 到 2GB 之间的任何大小

我需要知道的是:

a) 在尝试使用 File.ReadAllText 或我调用的自定义 StreamReader 函数时,标准文本文件的大小会引发内存不足错误 ReadFileString 例如

public static string ReadFileString(string path)
{
    // Use StreamReader to consume the entire text file.
using (StreamReader reader = new StreamReader(path))
{
    return reader.ReadToEnd();
    }
}

b) 是我的计算机内存(我有 16GB RAM - 复制时使用了 8GB)还是我在 C# 中使用的对象打开和复制文件失败。

归档时,我首先尝试使用我的自定义 ReadFileString 函数(见上文),如果 returns 0 字节的内容我尝试 File.ReadAllText 然后如果失败我尝试自定义函数来获取最后100,000行,今天早些时候调试错误确实不够

日志文件从创建新文件时的午夜开始,并记录一整天。我从来没有遇到过内存不足的错误,但是自从我调高了方法调用的频率后,日志记录就扩大了,这意味着文件大小也扩大了。

这是我获取最后 100,000 行的自定义函数。我想知道在没有 IT 抛出内存不足错误的情况下我可以获得多少行并且我根本没有获得最后几天日志文件的任何内容。

人们对保存 X 行所需的各种方法/内存的最大文件大小有何建议?获取尽可能多的日志文件的最佳方法是什么?

E.G 一些逐行循环直到遇到异常然后保存我所拥有的东西的方法。

这是我的 GetHundredThousandLines 方法,它记录到一个非常小的调试文件,因此我可以看到存档过程中发生了什么错误。

private bool GetHundredThousandLines(string logpath, string archivepath)
{
    bool success = false;

    int numberOfLines = 100000;


    if (!File.Exists(logpath))
    {
    this.LogDebug("GetHundredThousandLines - Cannot find path " + logpath + " to archive " + numberOfLines.ToString() + " lines");
    return false;
    }

    var queue = new Queue<string>(numberOfLines);

    using (FileStream fs = File.Open(logpath, FileMode.Open, FileAccess.Read, FileShare.Read))
    using (BufferedStream bs = new BufferedStream(fs))  // May not make much difference.
    using (StreamReader sr = new StreamReader(bs))
    {
    while (!sr.EndOfStream)
    {
        if (queue.Count == numberOfLines)
        {
        queue.Dequeue();
        }

        queue.Enqueue(sr.ReadLine() + "\r\n");
    }
    }

    // The queue now has our set of lines. So print to console, save to another file, etc.
    try
    {

    do
    {        
        File.AppendAllText(archivepath, queue.Dequeue(), Encoding.UTF8);
    } while (queue.Count > 0);


    }
    catch (IOException exception)
    {
    this.LogDebug("GetHundredThousandLines - I/O Error accessing daily log file with ReadFileString: " + exception.Message.ToString());
    }
    catch (System.OutOfMemoryException exception)
    {
    this.LogDebug("GetHundredThousandLines - Out of Memory Error accessing daily log file with ReadFileString: " + exception.Message.ToString());
    }
    catch (Exception exception)
    {
    this.LogDebug("GetHundredThousandLines - Exception accessing daily log file with ReadFileString: " + exception.Message.ToString());
    }


    if (File.Exists(archivepath))
    {
    this.LogDebug("GetHundredThousandLines - Log file exists at " + archivepath);
    success = true;
    }
    else
    {
    this.LogDebug("GetHundredThousandLines - Log file DOES NOT exist at " + archivepath);
    }

    return success;

}

如有任何帮助,我们将不胜感激。

谢谢

尝试: 将队列和流位置保持在 class 范围内,在出现内存不足异常时尝试 GC.Collect() 并再次调用函数。寻找流到最后一个位置并继续。 要么: 使用像 sqlite 这样的数据库并在每个 table.

中保留最新的 100000 条记录