将整数添加到列表时,System.outofmemoryException会抛出



我是一个非常业余的C#开发人员,他试图使用Visual Studio在MacOS上制作此控制台程序。我在学校做,但是我很自学,并且已经为此工作了不到两个星期,所以我很可能错过了一些简单的解决方案。

我已经制作了一个程序,该程序读取了一个填充质数的文本文件并将其转换为列表,然后开始生成素数,同时将它们添加到列表和文件中,并同时报告信息。一个新的。

这是我拥有的代码:

String fileLocation = "Prime Number List.txt"; //sets the file location to the root of where the program is stored
if (!File.Exists(fileLocation)) //tests if the file has already been created
{
    using (FileStream fs = File.Create(fileLocation))
    {
        Byte[] info = new UTF8Encoding(true).GetBytes("2"); //if not, it creates the file and creates the initial prime number of 2
        fs.Write(info, 0, info.Length);
    }
}

List<string> fileContents = File.ReadAllLines(fileLocation).ToList(); //imports the list of prime numbers from the file
List<int> listOfPrimeNumbers = fileContents.ConvertAll(s => Int32.Parse(s)); //converts the list into the integer variable type

int currentNumber = listOfPrimeNumbers[listOfPrimeNumbers.Count() - 1]; //sets the current number to the most recent prime number
bool isPrime; //initializing the primality test variable
int numbersGeneratedThisSession = 0; //initializing the variable for the amount of primes found in this session
var loopStart = DateTime.Now; //initializes the program start time, ignoring the time taken to load the file list
while (true)
{
    isPrime = true; //defaults the number to prime
    currentNumber++; //repeats the cycle for the next number
    double currentNumberRoot = Math.Sqrt(System.Convert.ToDouble(currentNumber));
    for (int i = 0; i < listOfPrimeNumbers.Count; i++) //cyles through all of the primes in the list. no reason to divide by composites, as any number divisible by a
                                                            //composite would be divisible by the prime factors of that composite anyway, thus if we were to divide by
                                                            //every number it would slow down the program
    {
        if (listOfPrimeNumbers[i] < Math.Sqrt(System.Convert.ToDouble(currentNumber))) //filters out any prime numbers greater than the square root of the current number, as any potential
                                                                                            //factor pair would have one of the values less than or equal to the square root
        {
            if (currentNumber % listOfPrimeNumbers[i] == 0) //checks for the even division of the current number by the current prime
            {
                isPrime = false; //if an even division is found, it reports that the number isn't false and breaks the loop
                break;
            }
        }
        else
            break; //if no even divisons are found, then it reaches this point with the primality test variable still true, and breaks the loop

    }
    if (isPrime) //this section of the code activates when the primality test variable is true
    {
        listOfPrimeNumbers.Add(currentNumber); //adds the new prime to the list
        File.AppendAllText(fileLocation, Environment.NewLine + currentNumber); //adds the new prime to the file on a new line
        numbersGeneratedThisSession++; //raises the counter for the prime numbers generated in this session
        var runtime = DateTime.Now - loopStart; //calculates the runtime of the program, excluding the time taken to load the file into the list
        int runtimeInSecs = (runtime.Milliseconds / 1000) + runtime.Seconds + (runtime.Minutes * 60) + (runtime.Hours * 360) + (runtime.Days * 86400); //converts the datetime var into an int of seconds
        int generationSpeed = runtimeInSecs == 0 ? 0 : numbersGeneratedThisSession / runtimeInSecs;
        Console.WriteLine("nI've generated {0} prime numbers, {1} of those being in the current session." +
                          "nI've been running for {2}, which means I've been generating numbers at a speed of {3} primes per second. " +
                          "nThe largest prime I've generated so far is {4}, which is {5} digits long.", 
                          listOfPrimeNumbers.Count(), numbersGeneratedThisSession, runtime, generationSpeed, currentNumber, currentNumber.ToString().Length);
    }
}

我一直在" listofprimenumbers.add(currentnumber("上获得例外;部分。我已经阅读了类似的问题,对他人问题的最常见解决方案是将gcallyverylargeobjects设置为true,以打破2GB的限制。这对我来说将是一个暂时的修复,但是随着时间的流逝,列表将不断遇到计算机功能的限制而不是Visual Studio Cap的极限。

会有一点。

我想知道是否有一些经验丰富的开发人员用来绕过此问题的技术,例如将数据分为多个列表,做与简化代码不同的事情等。我知道,由于我程序的性质是不可避免的,最终数据会增长太大,但是我试图将其推迟到现在的文件尽可能长的时间,而不是一半的演出,这是一个不合理的记忆崩溃程序。

我还要注意,我每天都在统计反馈(这意味着文件读数,写作和生成代码本身在这段时间内都没有受到影响(过去一周。我在启动的任何时间都没有问题,而且它的最后一次运行顺利进行(由于不记忆的例外,并没有崩溃(。今天我只是尝试再次开始时才遇到这个问题。

.net中的单个数组或列表都受所有限制:

  • 2GIB对象限制(除非启用gcAllowVeryLargeObjects(
  • 可用的过程内存(特别与32位过程有关(
  • 2,146,435,071个每个维度的项目(单字节值2,147,483,591(

如果您在这些问题附近获得,则是:您需要另一种方法。移至您将作为复合块视为的多个单独列表应充当定格间隙,但是...我认为这最终不是计算质数的非常可扩展的方法。

由于您正在使用他的程序搜索素数,因此,如果您只是尝试将其存储在上述内存中,就会用尽内存。

分开列表将有所帮助,但最终您会遇到相同的问题;5组3个项目是15个项目,分组与否。您将迅速填补记忆。

我认为您的问题可能在这里:

List<string> fileContents = File.ReadAllLines(fileLocation).ToList(); //imports the list of prime numbers from the file
List<int> listOfPrimeNumbers = fileContents.ConvertAll(s => Int32.Parse(s)); //converts the list into the integer variable type

这两个Lists<T>都是不必要的。您的文件中有运输返回(您的条目中正在插入Environment.NewLine(,因此假设您只想继续关闭的位置,则需要从该文件中恰好一个值:

//note that I used ReadLines, not ReadAllLines
 int lastNumber;
 if(!int.TryParse(File.ReadLines(fileLocation).ToList().Last(), out lastNumber))
 {
      //last value wasn't a valid integer.  Start over. 
      lastNumber = 1;
 }

然后,使用lastNumber执行所有逻辑,在素数时写入文件,并且根本不存储集合。这将使您的新限制因素成为目标计算机上的存储空间。如果您用完存储器的内存加载文件并获取最后一个字符串,则需要整理一些涉及向后读取文件的代码,但是由于这是一个更具学术的项目,我怀疑您需要将其视为远的。

最新更新