3 回答
TA贡献1824条经验 获得超8个赞
您可能需要阅读以下内容:Eric Lippert的“ “内存不足”不涉及物理内存 ”。
简而言之,并且非常简化,“内存不足”并不真正意味着可用内存量太小。最常见的原因是,在当前地址空间内,没有连续的内存部分足够大以服务于所需的分配。如果您有100个块,每个块4 MB,那么当您需要一个5 MB块时,这将无济于事。
关键点:
在我看来,我们称之为“进程存储器”的数据存储最好可视化为磁盘上的海量文件。
RAM可以看作仅仅是性能优化
程序消耗的虚拟内存总量实际上与它的性能没有太大关系
很少“用完RAM”会导致“内存不足”错误。它导致错误的性能,而不是错误,因为存储实际上在磁盘上这一事实的全部成本突然变得很重要。
TA贡献2019条经验 获得超9个赞
您可能已经发现,问题在于您正在尝试分配一个大的连续内存块,由于内存碎片,该内存块不起作用。如果我需要做您正在做的事情,请执行以下操作:
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];
}
然后,要获取特定索引,请使用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的东西。
- 3 回答
- 0 关注
- 722 浏览
添加回答
举报