[英]A workaround for a big multidimensional array (Jagged Array) C#?
我正在嘗試初始化三維數組以加載體素世界。
地圖的總大小應為( 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;
}
C#中單個對象的最大大小為2GB。 由於您正在創建一個多維數組而不是鋸齒狀數組(盡管您的方法的名稱),因此它是一個單個對象,需要包含所有這些項,而不是幾個。 如果您實際使用了鋸齒狀陣列,那么您將不會擁有包含所有這些數據的單個項目(即使總內存占用量稍大,而不是更小,它只是分散更多)。
默認情況下,陣列的最大大小為2千兆字節(GB)。 在64位環境中,可以通過在運行時環境中將gcAllowVeryLargeObjects配置元素的enabled屬性設置為true來避免大小限制。 但是, 該陣列仍將限制為總共40億個元素 ,並且在任何給定維度中最大索引為0X7FEFFFFF(對於字節數組和單字節結構數組,為0X7FFFFFC7)。
因此,盡管有上述答案,即使您將標志設置為允許更大的對象大小,該數組仍然限制為元素數量的32位限制。
編輯:您可能不得不重新設計以消除對多維數組的需求,因為您正在使用它(正如其他人所建議的那樣,在使用實際的鋸齒狀數組或其他一些維度集之間有幾種方法可以做到這一點)。 給定元素的數量的比例 ,它可能是最好使用設計,可動態分配對象/存儲器作為用於代替具有以陣列預先分配它。 (除非你不介意使用許多千兆字節的內存)EDITx2:也就是說,也許你可以定義定義填充內容的數據結構,而不是定義世界上每個可能的體素,甚至是“空”的體素。 (我假設絕大多數體素是“空的”而不是“填充”)
編輯:雖然不是微不足道的,特別是如果大多數空間被認為是“空的”,那么最好的辦法是引入某種空間樹,讓您有效地查詢您的世界,看看特定區域中的物體是什么。 例如: 八分之一 (如Eric所建議)或RTrees
非常感謝所有幫助我理解和解決問題的工作人員。
我嘗試了幾種解決方案,能夠加載大量數據並存儲在表中。 兩天后,這里是我的測試,最后是 可以將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 <>”允許最大的“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上找到自定義類在這里 。 初始化很長但效果很好!
/* ************************ */
/* 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...
}
如上所述創建此對象,無論是作為標准數組還是作為鋸齒狀數組,都將破壞允許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]; }
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.