我正在尝试初始化三维数组以加载体素世界。
地图的总大小应为( 2048/1024/2048 )。我试图初始化一个锯齿状数组的“int”但我抛出了一个内存异常。尺寸限制是多少? 我的桌子大小:2048 * 1024 * 2048 = 4'191'893'824
任何人都知道解决这个问题的方法吗?
// System.OutOfMemoryException here !
int[][][] matrice = CreateJaggedArray<int[][][]>(2048,1024,2048);
// if i try normal Initialization I also throws the exception
int[, ,] matrice = new int[2048,1024,2048];
static T CreateJaggedArray<T>(params int[] lengths)
{
return (T)InitializeJaggedArray(typeof(T).GetElementType(), 0, lengths);
}
static object InitializeJaggedArray(Type type, int index, int[] lengths)
{
Array array = Array.CreateInstance(type, lengths[index]);
Type elementType = type.GetElementType();
if (elementType != null)
{
for (int i = 0; i < lengths[index]; i++)
{
array.SetValue(
InitializeJaggedArray(elementType, index + 1, lengths), i);
}
}
return array;
}
答案 0 :(得分:4)
C#中单个对象的最大大小为2GB。由于您正在创建一个多维数组而不是锯齿状数组(尽管您的方法的名称),因此它是一个单个对象,需要包含所有这些项,而不是几个。如果您实际使用了锯齿状阵列,那么您将不会拥有包含所有这些数据的单个项目(即使总内存占用量稍大,而不是更小,它只是展开更多)
答案 1 :(得分:3)
来自MSDN documentation on Arrays(强调添加)
默认情况下,Array的最大大小为2千兆字节(GB)。在一个 在64位环境中,您可以通过设置来避免大小限制 gcAllowVeryLargeObjects配置元素的enabled属性 在运行时环境中为true。但是,数组仍将是 限制为总共40亿个元素,并且最大指数为 任何给定维度的0X7FEFFFFF(0X7FFFFFC7用于字节数组和 单字节结构数组。)
因此,尽管有上述答案,即使您将标志设置为允许更大的对象大小,该数组仍然限制为元素数量的32位限制。
编辑:您可能不得不重新设计以消除对当前使用它的多维数组的需求(正如其他人所建议的那样,在使用实际锯齿状数组,或其他一些维度集合)。给定元素数量的 scale ,最好使用动态分配对象/内存的设计,而不是必须预先分配它的数组。 (除非你不介意使用许多千兆字节的内存)EDITx2:也就是说,也许你可以定义定义填充内容的数据结构,而不是定义中每个可能的体素。世界,甚至是“空洞的”世界。 (我假设绝大多数体素都是“空的”而不是“填充”)
编辑:虽然不是微不足道的,特别是如果大多数空间被认为是“空的”,那么你最好的选择是引入某种空间树,让你有效地查询你的世界,看看特定的对象是什么。区域。例如:Octrees(正如Eric建议的那样)或RTrees
答案 2 :(得分:3)
非常感谢所有帮助我理解和解决问题的员工。
我尝试了几种解决方案,能够加载大量数据并存储在表格中。 两天之后,这是我的测试,最后是解决方案,可以将4'191'893'824 条目存储到一个数组中
我添加了我的最终解决方案,希望有人可以提供帮助
我记得目标:初始化整数数组[2048/1024/2048]以存储 4'191'893'824 数据
系统内存异常抛出
/* ******************** */
/* Jagged Array method */
/* ******************** */
// allocate the first dimension;
bigData = new int[2048][][];
for (int x = 0; x < 2048; x++)
{
// allocate the second dimension;
bigData[x] = new int[1024][];
for (int y = 0; y < 1024; y++)
{
// the last dimension allocation
bigData[x][y] = new int[2048];
}
}
系统内存异常抛出(将大数组分成几个小数组..不起作用,因为“List&lt;&gt;”允许最大的“2GB”Ram allocution就像一个简单的数组不幸。)
/* ******************** */
/* List method */
/* ******************** */
List<int[,,]> bigData = new List<int[,,]>(512);
for (int a = 0; a < 512; a++)
{
bigData.Add(new int[256, 128, 256]);
}
我终于找到了解决方案! 使用“Memory Mapped File”类包含虚拟内存中文件的内容。
MemoryMappedFile MSDN 与我在codeproject here上找到的自定义类一起使用。初始化很长但效果很好!
/* ************************ */
/* MemoryMappedFile method */
/* ************************ */
string path = AppDomain.CurrentDomain.BaseDirectory;
var myList = new GenericMemoryMappedArray<int>(2048L*1024L*2048L, path);
using (myList)
{
myList.AutoGrow = false;
/*
for (int a = 0; a < (2048L * 1024L * 2048L); a++)
{
myList[a] = a;
}
*/
myList[12456] = 8;
myList[1939848234] = 1;
// etc...
}
答案 3 :(得分:1)
如上所述创建此对象,无论是作为标准数组还是作为锯齿状数组,都会破坏允许CPU执行的引用局部性。我建议您使用这样的结构:
class BigArray
{
ArrayCell[,,] arrayCell = new ArrayCell[32,16,32];
public int this[int i, int j, int k]
{
get { return (arrayCell[i/64, j/64, k/64])[i%64, j%64, k%16]; }
}
}
class ArrayCell
{
int[,,] cell = new int[64,64,64];
public int this[int i, int j, int k]
{
get { return cell[i,j,k]; }
}
}