你能使用List <list <struct>&gt;绕过2gb对象限制?</list <struct>

时间:2012-03-27 15:36:31

标签: c# memory memory-management reference 64-bit

我遇到了c#中的2gb对象限制(由于某些令人讨厌的原因,这甚至适用于64位),并且有大量的结构集(估计大小为4.2 gig)。

现在很明显使用List会给我一个大小为4.2gb的列表,但是会使用由较小的列表组成的列表,而这些列表又包含一部分结构,允许我跳过这个限制吗?

我的理由是,它只是CLR中的硬编码限制,阻止我在64位平台上实例化9gig对象,而且它与系统资源完全无关。 Lists和Arrays也是引用类型,因此包含列表的List实际上只包含对每个列表的引用。因此,没有任何一个物体超过了尺寸限制。

有什么理由说这不起作用?我现在自己尝试一下,但我手边没有内存分析器来验证。

5 个答案:

答案 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
}