我遇到了c#中的2gb对象限制(由于某些令人讨厌的原因,这甚至适用于64位),并且有大量的结构集(估计大小为4.2 gig)。
现在很明显使用List会给我一个大小为4.2gb的列表,但是会使用由较小的列表组成的列表,而这些列表又包含一部分结构,允许我跳过这个限制吗?
我的理由是,它只是CLR中的硬编码限制,阻止我在64位平台上实例化9gig对象,而且它与系统资源完全无关。 Lists和Arrays也是引用类型,因此包含列表的List实际上只包含对每个列表的引用。因此,没有任何一个物体超过了尺寸限制。
有什么理由说这不起作用?我现在自己尝试一下,但我手边没有内存分析器来验证。
答案 0 :(得分:13)
现在很明显使用List会给我一个大小为4.2gb的列表,但是会使用由较小的列表组成的列表,而这些列表又包含一部分结构,允许我跳过这个限制吗?
是的 - 但是,如果您正在尝试解决此限制,我会考虑自己使用数组,而不是让List<T>
类管理数组。
CLR中的2gb单个对象限制就是单个对象实例。当你创建一个结构数组(List<T>
在内部使用)时,整个数组就是CLR中的“一个对象实例”。但是,通过使用List<List<T>>
或锯齿状数组,每个内部列表/数组都是一个单独的对象,它允许您有效地拥有所需的任何大小的对象。
CLR团队实际上就此发表了博客,并提供了sample BigArray<T>
实施,其行为类似于单个List<T>
,但内部为您执行“阻止”管理。这是获取&gt; 2gb列表的另一种选择。
请注意,.NET 4.5可以选择提供larger than 2gb objects on x64,但是您必须明确选择使用。
答案 1 :(得分:2)
List
保存4或8个字节的引用,具体取决于您是以32位还是64位模式运行,因此如果引用的2GB对象不会增加实际List
1}}大小为2 GB,但它只会增加引用该对象所需的字节数。
这将允许您引用数百万个对象,每个对象可以是2GB。如果List
中有4个对象,每个对象为2 GB,则List
引用的对象数量为8 GB,但List
对象只会耗尽额外4 * 8 = 32字节。
在List
达到2GB限制之前,您可以在32位计算机上保留的引用数为53687万,而在64位计算机上则为268.43百万。
5.36亿个参考* 2 GB =很多数据!
P.S。 Reed指出,上述内容适用于引用类型,但不适用于值类型。因此,如果您持有值类型,那么您的解决方法是有效的。有关详细信息,请参阅下面的评论。
答案 2 :(得分:0)
这里有一个关于这个主题的有趣帖子:
http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx
关于编写自己的&#39; BigArray&#39;对象
答案 3 :(得分:0)
在4.5之前的.NET版本中,最大对象大小为2GB。从4.5开始,如果启用gcAllowVeryLargeObjects,您可以分配更大的对象。请注意,string
的限制不受影响,但“数组”也应该包含“列表”,因为列表由数组支持。
答案 4 :(得分:0)
class HugeList<T>
{
private const int PAGE_SIZE = 102400;
private const int ALLOC_STEP = 1024;
private T[][] _rowIndexes;
private int _currentPage = -1;
private int _nextItemIndex = PAGE_SIZE;
private int _pageCount = 0;
private int _itemCount = 0;
#region Internals
private void AddPage()
{
if (++_currentPage == _pageCount)
ExtendPages();
_rowIndexes[_currentPage] = new T[PAGE_SIZE];
_nextItemIndex = 0;
}
private void ExtendPages()
{
if (_rowIndexes == null)
{
_rowIndexes = new T[ALLOC_STEP][];
}
else
{
T[][] rowIndexes = new T[_rowIndexes.Length + ALLOC_STEP][];
Array.Copy(_rowIndexes, rowIndexes, _rowIndexes.Length);
_rowIndexes = rowIndexes;
}
_pageCount = _rowIndexes.Length;
}
#endregion Internals
#region Public
public int Count
{
get { return _itemCount; }
}
public void Add(T item)
{
if (_nextItemIndex == PAGE_SIZE)
AddPage();
_itemCount++;
_rowIndexes[_currentPage][_nextItemIndex++] = item;
}
public T this[int index]
{
get { return _rowIndexes[index / PAGE_SIZE][index % PAGE_SIZE]; }
set { _rowIndexes[index / PAGE_SIZE][index % PAGE_SIZE] = value; }
}
#endregion Public
}