C# ';System.OutOfMemoryException';在仍有大量可用内存时抛出
这是我的代码:C# ';System.OutOfMemoryException';在仍有大量可用内存时抛出,c#,memory-management,out-of-memory,C#,Memory Management,Out Of Memory,这是我的代码: int size = 100000000; double sizeInMegabytes = (size * 8.0) / 1024.0 / 1024.0; //762 mb double[] randomNumbers = new double[size]; 例外情况: 引发了“System.OutOfMemoryException”类型的异常 我在这台机器上有4GB内存2.5GB是空闲的当我开始运行时,电脑上显然有足够的空间来处理762mb的100000000个随机数。给定
int size = 100000000;
double sizeInMegabytes = (size * 8.0) / 1024.0 / 1024.0; //762 mb
double[] randomNumbers = new double[size];
例外情况:
引发了“System.OutOfMemoryException”类型的异常
我在这台机器上有4GB内存2.5GB是空闲的当我开始运行时,电脑上显然有足够的空间来处理762mb的100000000个随机数。给定可用内存,我需要存储尽可能多的随机数。当我投入生产时,盒子上会有12GB,我想利用它
CLR是否将我限制为默认的最大内存?我如何要求更多?
更新
我认为,如果问题是由于内存碎片造成的,那么将其分解成更小的块并逐渐增加内存需求将有所帮助,但这并不我无法通过256mb的总数组列表大小,无论我如何调整块大小
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()));
}
}
将Windows进程限制增加到3gb。(通过boot.ini或Vista引导管理器)您可能需要阅读Eric Lippert的以下内容: 简而言之,非常简单,“内存不足”并不意味着可用内存太少。最常见的原因是,在当前地址空间中,没有足够大的连续内存部分来满足所需的分配。如果您有100个块,每个块都是4MB大的,那么当您需要一个5MB块时,这对您没有帮助 要点:
- 在我看来,我们称之为“进程内存”的数据存储最好可视化为磁盘上的海量文件
- RAM可以看作仅仅是一种性能优化
- 您的程序所消耗的虚拟内存总量实际上与其性能没有太大关系
- “内存不足”很少会导致“内存不足”错误。它不是一个错误,而是导致性能差,因为存储实际上位于磁盘上这一事实的全部成本突然变得重要起来
- 您可以尝试使用/3GB(正如其他人所建议的那样)
- 或者切换到64位操作系统
- 或者修改算法,使其不需要大量内存。可能会分配一些较小(相对)的内存块
- 您没有连续的内存块来分配762MB,您的内存是碎片化的,分配器无法找到足够大的洞来分配所需的内存
32位windows的进程内存限制为2GB。其他人提到的/3GB引导选项将使3GB只剩下1gb供操作系统内核使用。现实地说,如果您想使用2GB以上的数据而不感到麻烦,则需要64位操作系统。这也克服了一个问题,即虽然您可能有4GB的物理RAM,但视频卡所需的地址空间可能会使该内存的一个较大的卡盘无法使用-通常约为500MB。好吧,我遇到了一个类似的大数据集问题,试图迫使应用程序使用如此多的数据并不是真正正确的选择。我能给你的最好建议是,如果可能的话,把数据分成小块处理。因为处理这么多数据,问题迟早会回来的。另外,您无法知道将运行您的应用程序的每台计算机的配置,因此在另一台电脑上总是有发生异常的风险。我建议不要使用/3GB windows启动选项。除此之外(对一个行为不好的应用程序这样做太过分了,而且可能无论如何也解决不了您的问题),它可能会导致很多不稳定性 许多Windows驱动程序都没有使用此选项进行测试,因此很多驱动程序都假设用户模式指针始终指向较低的2GB地址空间。这意味着它们可能会严重破坏/3GB 但是,Windows通常将32位进程限制为2GB地址空间。 但这并不意味着您应该期望能够分配2GB 地址空间中已经充斥着各种分配的数据。还有堆栈、所有加载的程序集、静态变量等等。不能保证任何地方都会有800MB的连续未分配内存 分配2400MB块可能会更好。或4个200MB块。更小的分配更容易在零碎的内存空间中找到空间
无论如何,如果要将其部署到12GB的机器上,您需要将其作为64位应用程序运行,这将解决所有问题。如果您需要如此大的结构,也许可以利用内存映射文件。 这篇文章可能会有帮助: 有限合伙人,
Dejan与其分配大量数组,不如尝试使用迭代器?这些是延迟执行的,这意味着值只有在foreach语句中请求时才会生成;您不应该以这种方式耗尽内存:
private static IEnumerable<double> MakeRandomNumbers(int numberOfRandomNumbers)
{
for (int i = 0; i < numberOfRandomNumbers; i++)
{
yield return randomGenerator.GetAnotherRandomNumber();
}
}
...
// Hooray, we won't run out of memory!
foreach(var number in MakeRandomNumbers(int.MaxValue))
{
Console.WriteLine(number);
}
私有静态IEnumerable MakeRandomNumbers(int numberOfRandomNumbers)
{
for(int i=0;i
上面的代码将生成任意数量的随机数,但只能生成通过foreach语句请求的随机数。这样就不会耗尽内存
或者,如果您必须将它们全部放在一个位置,请将它们存储在文件中,而不是内存中。从32位更改为64位对我来说很有用-如果您使用的是64位pc,并且它不需要端口,那么值得一试。正如您可能发现的,问题是您正在尝试分配一个大的连续内存块,由于内存碎片,无法正常工作。如果我需要做你正在做的事情,我会做以下事情:
int sizeA = 10000,
sizeB = 10000;
double sizeInMegabytes = (sizeA * sizeB * 8.0) / 1024.0 / 1024.0; //762 mb
double[][] randomNumbers = new double[sizeA][];
for (int i = 0; i < randomNumbers.Length; i++)
{
randomNumbers[i] = new double[sizeB];
}
call "$(DevEnvDir)..\..\vc\vcvarsall.bat" x86
"$(DevEnvDir)..\..\vc\bin\EditBin.exe" "$(TargetPath)" /LARGEADDRESSAWARE
需要注意的是,虽然
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);
}
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
var jsSerializer = new JavaScriptSerializer();
jsSerializer.MaxJsonLength = Int32.MaxValue;
call "$(DevEnvDir)..\..\vc\vcvarsall.bat" x86
"$(DevEnvDir)..\..\vc\bin\EditBin.exe" "$(TargetPath)" /LARGEADDRESSAWARE