将整数添加到列表时抛出System.OutOfMemoryException

KAT*_*ech -3 c# out-of-memory

我是一个非常业余的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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我一直在"listOfPrimeNumbers.Add(currentNumber);"上获得异常.部分.我已经阅读了类似的问题,而对其他人的问题最常见的解决方案是将gcAllowVeryLargeObjects设置为true,以打破2GB的限制.这对我来说是暂时的修复,但是随着时间的推移,这个列表会不断变大,当它达到计算机功能的极限而不是视觉工作室的上限时,会有一个点.

我想知道是否有某种技术可供更有经验的开发人员用来规避这个问题,比如将数据拆分成多个列表,做一些不同于我的工作来简化代码等等.我知道由于我的性质程序是不可避免的,最终数据会变得太大,但我试图推迟,因为现在的文件不到半个演出,这是一个不合理的少量内存崩溃程序.

我还要注意到,在我过去一周工作的统计反馈(意味着文件读取,写入和生成代码本身在此期间基本未被触及)的过程中,我每天运行此程序大约一个小时.我在任何时候启动都没有问题,最后一次运行顺利(由于内存不足异常没有崩溃).我今天尝试重新启动时才遇到这个问题.

Mar*_*ell 8

.NET中的各个数组或列表受以下所有绑定:

  • 2GiB对象限制(除非gcAllowVeryLargeObjects已启用)
  • 可用的进程内存(特别适用于32位进程)
  • 每维度2,146,435,071项(单字节值为2,147,483,591)

如果你接近这些问题,那么是的:你需要另一种方法.移动到您视为复合块的多个单独列表应该作为一个间隙,但是......我不认为这最终是一种非常可扩展的计算素数的方法.