猿问

当仍有大量可用内存时,抛出“ System.OutOfMemoryException”

这是我的代码:


int size = 100000000;

double sizeInMegabytes = (size * 8.0) / 1024.0 / 1024.0; //762 mb

double[] randomNumbers = new double[size];

异常:引发了类型为'System.OutOfMemoryException'的异常。


我在这台机器上有4GB内存,当我开始运行时有2.5GB可用空间,显然PC上有足够的空间来处理762mb的100000000随机数。给定可用内存,我需要存储尽可能多的随机数。当我投入生产时,包装盒上将有12GB,我想利用它。


CLR是否将我限制为默认的最大内存开始?以及我如何要求更多?


更新资料


我认为如果问题是由于内存碎片造成的话,将它分成较小的块并逐步增加我的内存需求会有所帮助,但是不管我做什么调整blockSize,我都无法超过256mb的ArrayList大小。


private static IRandomGenerator rnd = new MersenneTwister();

private static IDistribution dist = new DiscreteNormalDistribution(1048576);

private static List<double> ndRandomNumbers = new List<double>();


private static void AddNDRandomNumbers(int numberOfRandomNumbers) {

    for (int i = 0; i < numberOfRandomNumbers; i++) {

      ndRandomNumbers.Add(dist.ICDF(rnd.nextUniform()));                

  }

}

从我的主要方法:


int blockSize = 1000000;


while (true) {

  try

  {

    AddNDRandomNumbers(blockSize);                    

  }

  catch (System.OutOfMemoryException ex)

  {

    break;

  }

}            

double arrayTotalSizeInMegabytes = (ndRandomNumbers.Count * 8.0) / 1024.0 / 1024.0;


喵喵时光机
浏览 723回答 3
3回答

有只小跳蛙

您可能需要阅读以下内容:Eric Lippert的“&nbsp;“内存不足”不涉及物理内存&nbsp;”。简而言之,并且非常简化,“内存不足”并不真正意味着可用内存量太小。最常见的原因是,在当前地址空间内,没有连续的内存部分足够大以服务于所需的分配。如果您有100个块,每个块4 MB,那么当您需要一个5 MB块时,这将无济于事。关键点:在我看来,我们称之为“进程存储器”的数据存储最好可视化为磁盘上的海量文件。RAM可以看作仅仅是性能优化程序消耗的虚拟内存总量实际上与它的性能没有太大关系很少“用完RAM”会导致“内存不足”错误。它导致错误的性能,而不是错误,因为存储实际上在磁盘上这一事实的全部成本突然变得很重要。

慕少森

您可能已经发现,问题在于您正在尝试分配一个大的连续内存块,由于内存碎片,该内存块不起作用。如果我需要做您正在做的事情,请执行以下操作:int sizeA = 10000,    sizeB = 10000;double sizeInMegabytes = (sizeA * sizeB * 8.0) / 1024.0 / 1024.0; //762 mbdouble[][] randomNumbers = new double[sizeA][];for (int i = 0; i < randomNumbers.Length; i++){    randomNumbers[i] = new double[sizeB];}然后,要获取特定索引,请使用randomNumbers[i / sizeB][i % sizeB]。如果您始终按顺序访问这些值,则另一个选择可能是使用重载的构造函数来指定种子。这样,您将获得一个半随机数(如DateTime.Now.Ticks),将其存储在变量中,然后无论何时开始浏览列表,都将使用原始种子创建一个新的Random实例:private static int randSeed = (int)DateTime.Now.Ticks;  //Must stay the same unless you want to get different random numbers.private static Random GetNewRandomIterator(){    return new Random(randSeed);}重要的是要注意,尽管该问题通常是由于地址空间不足所致,但并未列出其他许多问题,例如2GB CLR对象大小限制(在ShuggyCoUk在同一博客上)掩盖了内存碎片,并且没有提及页面文件大小的影响(以及如何使用CreateFileMapping函数解决)。2GB的限制意味着randomNumbers 必须小于2GB。由于数组是类,并且它们自身具有一些开销,因此这意味着数组double必须小于2 ^ 31。我不确定长度必须比2 ^ 31小多少,但是.NET数组的开销?表示12-16个字节。内存碎片与HDD碎片非常相似。您可能有2GB的地址空间,但是在创建和销毁对象时,这些值之间会有间隙。如果这些间隙对于您的大物件而言太小,并且无法请求额外的空间,那么您将获得System.OutOfMemoryException。例如,如果您创建200万个1024字节的对象,则您使用的是1.9GB。如果删除地址不是3的倍数的每个对象,则将使用.6GB的内存,但是它将在整个地址空间中分布,中间有2024字节的开放块。如果您需要创建一个大小为.2GB的对象,则将无法执行该操作,因为没有足够大的块可容纳该块,并且无法获得额外的空间(假定为32位环境)。解决此问题的方法可能是使用较小的对象,减少存储在内存中的数据量或使用内存管理算法限制/防止内存碎片。应该注意的是,除非您正在开发使用大量内存的大型程序,否则这将不是问题。也,由于大多数程序从操作系统请求工作内存,并且不请求文件映射,因此它们将受到系统RAM和页面文件大小的限制。那比预期更长。希望它可以帮助某人。我发布它是因为我遇到了在System.OutOfMemoryException具有24GB RAM的系统上运行x64程序的问题,即使我的阵列仅容纳2GB的东西。
随时随地看视频慕课网APP
我要回答