Список, работающий с многократными блоками

Список - обертка по множеству. В то время как вы добавляете пункты к списку, он создает большее и большее тайное множество (и предыдущее множество - собранный мусор). Но если вы будете рассматривать большие списки в какой-то момент, то вы получите OutOfMemoryException, даже если будет свободная память из-за фрагментации памяти. Я ищу внедрение ICollection, которое работало бы с набором множеств, тайных подобный какой MemoryTributary делает.

Обновление.

Я нашел внедрение BigArray здесь:

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

While it tries to solve other problem (creating an array of >2GB size), it solves my problem too. But this implementation is not full and even does not compile. So if I don't find any better, I will improve this one and use it.

3
@JonSkeet, 400 МБ удваиваются
добавлено автор SiberianGuy, источник
@JonSkeet, 400 МБ. Я управляю x64.NET 4, но я должен поддержать x86 пользовательское слишком (настольное приложение).
добавлено автор SiberianGuy, источник
Как большой ваша коллекция на самом деле собирается добраться? Для ссылочных типов данные, используемые самими объектами, обычно заканчивали бы тем, что были намного больше, чем множество, таким образом, это редко - проблема.
добавлено автор Jon Skeet, источник
400 МБ, или 400 миллионов? (Фактор 8 различий!) Кроме того, какая архитектура ЦП вы продолжаетесь, и что версия.NET?.NET 4.5 на x64 позволяет большие множества, если вы включаете правильный флаг.
добавлено автор Jon Skeet, источник
Что , проблема в ситуациях низкой памяти - факт, который выстраивает больше, чем вокруг 85K, идут на "кучу" для больших объектов, и поэтому не будет перемещен в памяти, чтобы создать место для новых отчислений. Это может вызвать основную фрагментацию памяти и является проблемой, с которой у нас были проблемы. И множества удваиваются, еще хуже - они идут на "кучу" для больших объектов если there' s больше чем 1000 из них! Так it' s не полное использование памяти that' s проблема; вместо этого, it' s фрагментация, вызванная объектами, помещаемыми в "кучу" для больших объектов.
добавлено автор Matthew Watson, источник

2 ответы

Можно инициализировать Список со способностью, если у вас есть грубая оценка максимального размера. Насколько я знаю, это избежит тяжелого случая сборки мусора (со старыми меньшими массивами), который мог бы также избежать фрагментации памяти.

1
добавлено
Это doesn' t помогают решить описанную проблему. Поскольку скоро я определяю, что способность миллионов и миллионов удваивается, она попытается создать множество соответствующего размера. Но это потерпит неудачу с OutOfMemoryException из-за ситуации, описанной рассматриваемым Мэтью Уотсоном, комментирует раздел. Если вы - curions о рабочем решении, пожалуйста, посмотрите на мой ответ.
добавлено автор SiberianGuy, источник

Я не нашел хорошего внедрения. Таким образом, я написал моему собственному ChunkyList. Обычно ChunkyList - Список обертки множеств. Первоначально у блока есть размер 1, но это умножается на два (когда это достигает MaxBlockSize, следующий блок создается), каждый раз, когда необходимо расширить текущий блок (поведение, подобное Списку).

Вот универсальный ChunkyList:

public class ChunkyList : IList
{
    public ChunkyList()
    {
        MaxBlockSize = 65536;
    }

    public ChunkyList(int maxBlockSize)
    {
        MaxBlockSize = maxBlockSize;
    }

    private List _blocks = new List();

    public int Count { get; private set; }

    public int MaxBlockSize { get; private set; }

    public bool IsReadOnly
    {
        get { throw new NotImplementedException(); }
    }

    public IEnumerator GetEnumerator()
    {
        var index = 0;
        foreach (var items in _blocks)
            foreach (var item in items)
            {
                yield return item;
                if (Count <= ++index)
                    break;
            }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public void Add(T item)
    {
        var indexInsideBlock = GetIndexInsideBlock(Count);
        if (indexInsideBlock == 0)
            _blocks.Add(new T[1]);
        else
        {
            var lastBlockIndex = _blocks.Count - 1;
            var lastBlock = _blocks[lastBlockIndex];
            if(indexInsideBlock >= lastBlock.Length)
            {
                var newBlockSize = lastBlock.Length*2;
                if (newBlockSize >= MaxBlockSize)
                    newBlockSize = MaxBlockSize;

                _blocks[lastBlockIndex] = new T[newBlockSize];
                Array.Copy(lastBlock, _blocks[lastBlockIndex], lastBlock.Length);
            }
        }

        _blocks[GetBlockIndex(Count)][indexInsideBlock] = item;

        Count++;
    }

    public void AddRange(IEnumerable items)
    {
        foreach (var item in items)
            Add(item);
    }

    public void Clear()
    {
        throw new NotImplementedException();
    }

    public bool Contains(T item)
    {
        throw new NotImplementedException();
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        throw new NotImplementedException();
    }

    public bool Remove(T item)
    {
        throw new NotImplementedException();
    }

    public int IndexOf(T item)
    {
        throw new NotImplementedException();
    }

    public void Insert(int index, T item)
    {
        throw new NotImplementedException();
    }

    public void RemoveAt(int index)
    {
        throw new NotImplementedException();
    }

    public T this[int index]
    {
        get
        {
            if (index >= Count)
                throw new ArgumentOutOfRangeException("index");

            var blockIndex = GetBlockIndex(index);
            var block = _blocks[blockIndex];

            return block[GetIndexInsideBlock(index)];
        }
        set { throw new NotImplementedException(); }
    }

    private int GetBlockIndex(int index)
    {
        return index/MaxBlockSize;
    }

    private long GetIndexInsideBlock(int index)
    {
        return index % MaxBlockSize;
    }
}

И вот тесты, которые доказывают это внедрение работы:

 [TestClass]
    public class ChunkyListTests
    {
        [TestMethod]
         public void GetEnumerator_NoItems()
         {
             var chunkyList = new ChunkyList();

             var wasInsideForeach = false;
             foreach (var item in chunkyList)
                 wasInsideForeach = true;

             Assert.IsFalse(wasInsideForeach);
         }

        [TestMethod]
        public void GetEnumerator_MaxBlockSizeOfThreeWithThreeItems()
        {
            var chunkyList = new ChunkyList (3) { 1, 2, 3 };

            var wasInsideForeach = false;
            var iteratedItems = new List();
            foreach (var item in chunkyList)
            {
                wasInsideForeach = true;
                iteratedItems.Add(item);
            }

            Assert.IsTrue(wasInsideForeach);
            CollectionAssert.AreEqual(new List { 1, 2, 3 }, iteratedItems);
        }

        [TestMethod]
        public void GetEnumerator_MaxBlockSizeOfTwoWithThreeItems()
        {
            var chunkyList = new ChunkyList(2) {1,2,3};
            var wasInsideForeach = false;
            var iteratedItems = new List();

            foreach (var item in chunkyList)
            {
                wasInsideForeach = true;
                iteratedItems.Add(item);
            }

            Assert.IsTrue(wasInsideForeach);
            CollectionAssert.AreEqual(new List() { 1, 2, 3 }, iteratedItems);
            Assert.AreEqual(chunkyList.MaxBlockSize, 2);
        }
    }

P. S. Я осуществил только те методы IList, которые используются в моем коде. Таким образом, вы можете улучшить это внедрение.

0
добавлено
Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot