繁体   English   中英

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

[英]Can you use List<List<struct>> to get around the 2gb object limit?

我正在运行c#中的2gb对象限制(由于某些令人讨厌的原因,这甚至适用于64位),其中包含大量结构(总共大小为4.2 gig)。

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

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

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

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

是的 - 但是,如果您正在尝试解决此限制,我会考虑自己使用数组,而不是让List<T>类管理数组。

CLR中的2gb单个对象限制正好是单个对象实例。 当你创建一个struct的数组( List<T>内部使用)时,整个数组是CLR中的“一个对象实例”。 但是,通过使用List<List<T>>或锯齿状数组,每个内部列表/数组都是一个单独的对象,它允许您有效地拥有所需的任何大小的对象。

CLR团队实际上在博客上写了这个,并提供了一个示例BigArray<T>实现,其作用类似于单个List<T> ,但在内部为您执行“阻止”管理。 这是获得> 2gb列表的另一种选择。

请注意,.NET 4.5可以选择在x64上提供大于2gb的对象 ,但是您必须明确选择使用它。

List包含4或8个字节的引用,具体取决于您是在32位还是64位模式下运行,因此如果您引用的2GB对象不会将实际的List大小增加到2 GB,但它只会通过引用该对象所需的字节数来增加它。

这将允许您引用数百万个对象,每个对象可以是2GB。 如果你有在4名对象List ,且各自为2 GB,那么你将有8 GB值得引用对象的List ,但List对象将只使用一个额外的4×8 = 32个字节。

List达到2GB限制之前,您可以在32位计算机上保留的引用数为536.87百万,而在64位计算机上则为268.43百万。

5.36亿个参考* 2 GB =很多数据!

PS Reed指出,上述内容适用于引用类型,但不适用于值类型。 因此,如果您持有值类型,那么您的解决方法是有效的。 有关详细信息,请参阅下面的评论。

在4.5之前的.NET版本中,最大对象大小为2GB。 从4.5开始,如果启用了gcAllowVeryLargeObjects,则可以分配更大的对象。 请注意, string的限制不受影响,但“数组”也应该涵盖“列表”,因为列表由数组支持。

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
}

这里有一篇关于这个主题的有趣帖子:

http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx

其中讨论了编写自己的“BigArray”对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM