C# огромный размер 2-тусклые массивы

Я должен объявить квадратные матрицы в C# WinForms больше чем с 20 000 объектов подряд. Я считал предел размера объекта .NET приблизительно на 2 ГБ в 32 битах и также тот же случай в ОС на 64 бита. Таким образом, поскольку я понял, что единственный ответ - использует небезопасный код, или отдельная библиотека создала скручивание жгутов компилятор C++.

Проблема для меня стоит, потому что ushort[20000,20000] меньше затем 2 ГБ, но на самом деле я не могу выделить даже 700 МБ памяти. Мой предел составляет 650 МБ, и я не понимаю, почему - у меня есть WinXP на 32 бита с 3 ГБ памяти. Я пытался использовать Маршала. AllocHGlobal (700 <<20), но это бросает OutOfMemoryException, возвраты GC.GetTotalMemory 4.5 МБ прежде, чем попытаться выделить память.

Я нашел только, что, поскольку многие люди говорят, используют небезопасный код, но я не могу найти пример того, как объявить 2-тусклый массив в "куче" (любой стек не может сохранить настолько огромный объем данных), и как работать с ним с помощью указателей. Это - чистый код C++ в небезопасном {} скобки?

PS. Не спрашивайте, ПОЧЕМУ мне нужно так огромные массивы..., но если Вы хотите - я должен проанализировать тексты (например, книги) и найденная партия индексов. Таким образом, ответ - матрицы отношений между словами

Править: Мог кто-то предоставлять небольшому примеру работы с матрицами с помощью указателей в небезопасном коде. Я знаю, что менее чем 32 бита, невозможно выделить больше места, но я провел много времени в поиске с помощью Google такого примера и НИЧЕГО не нашел

6
задан Cheburek 7 April 2010 в 17:09
поделиться

6 ответов

Я так счастлива! :) Недавно поигрался с предметной проблемой - попытался решить ее с помощью базы данных, но только обнаружил, что этот способ далек от совершенства. Матрица [20000,20000] реализована в виде единой таблицы. Даже при правильной настройке индексов время, необходимое только для создания более 400 миллионов записей, на моем компьютере составляет около 1 часа. Для меня это не критично. Затем я запустил алгоритм для работы с этой матрицей (требуется дважды соединить одну и ту же таблицу!), И после того, как он проработал более получаса, он не сделал ни единого шага. После этого я понял, что единственный способ - найти способ работать с такой матрицей только в памяти и снова вернуться на C #.

Я создал пилотное приложение, чтобы протестировать процесс выделения памяти и определить, где именно процесс выделения останавливается с использованием различных структур.

Как было сказано в моем первом посте, с помощью 2-мерных массивов можно выделить только 650 МБ под 32-битным WinXP. Результаты после использования Win7 и 64-битной компиляции также были печальными - менее 700 МБ.

Я использовал JAGGED ARRAYS [] [] вместо одного двухмерного массива [,], и результаты вы можете увидеть ниже:

Скомпилировано в режиме выпуска как 32-битное приложение - WinXP 32bit 3GB Phys. мем. - 1,45 ГБ Скомпилировано в режиме выпуска как 64-битное приложение - Win7 64-битное 2 ГБ под ВМ - 7,5 ГБ

- Источники приложений, которые я использовал для тестирования, прилагаются к этому сообщение. Я не могу найти здесь, как прикрепить исходные файлы, поэтому просто опишите часть дизайна и поместите сюда ручной код. Создайте приложение WinForms. Поместите в форму такие элементы управления с именами по умолчанию: 1 кнопка, 1 numericUpDown и 1 список В файле .cs добавьте следующий код и выполните.

private void button1_Click(object sender, EventArgs e)
        {
            //Log(string.Format("Memory used before collection: {0}", GC.GetTotalMemory(false)));
            GC.Collect();
            //Log(string.Format("Memory used after collection: {0}", GC.GetTotalMemory(true)));
            listBox1.Items.Clear();
            if (string.IsNullOrEmpty(numericUpDown1.Text )) {
                Log("Enter integer value");
            }else{
                int val = (int) numericUpDown1.Value;
                Log(TryAllocate(val));
            }
        }

        /// <summary>
        /// Memory Test method
        /// </summary>
        /// <param name="rowLen">in MB</param>
        private IEnumerable<string> TryAllocate(int rowLen) {
            var r = new List<string>();
            r.Add ( string.Format("Allocating using jagged array with overall size (MB) = {0}", ((long)rowLen*rowLen*Marshal.SizeOf(typeof(int))) >> 20) );
            try {
                var ar = new int[rowLen][];
                for (int i = 0; i < ar.Length; i++) {
                    try {
                        ar[i] = new int[rowLen];
                    }
                    catch (Exception e) {
                        r.Add ( string.Format("Unable to allocate memory on step {0}. Allocated {1} MB", i
                            , ((long)rowLen*i*Marshal.SizeOf(typeof(int))) >> 20 ));
                        break;
                    }
                }
                r.Add("Memory was successfully allocated");
            }
            catch (Exception e) {
                r.Add(e.Message + e.StackTrace);
            }
            return r;
        }

        #region Logging

        private void Log(string s) {
            listBox1.Items.Add(s);
        }

        private void Log(IEnumerable<string> s)
        {
            if (s != null) {
                foreach (var ss in s) {
                    listBox1.Items.Add ( ss );
                }
            }
        }

        #endregion

Проблема решена для меня. Ребята, заранее спасибо!

2
ответ дан 9 December 2019 в 22:32
поделиться

Если бы вы объяснили, что вы пытаетесь сделать, вам будет легче помочь. Может быть, есть способы лучше, чем сразу выделить такой огромный объем памяти.

Редизайн также является выбором номер один в этом замечательном сообщении в блоге:

BigArray, обойти ограничение на размер массива в 2 ГБ

В этой статье предлагаются следующие варианты:

0
ответ дан 9 December 2019 в 22:32
поделиться

Зачем нужен огромный двумерный массив? Вы можете смоделировать это, например, с зазубренным массивом - ushort [] [] - почти так же быстро, и вы не достигнете того же ограничения для одного объекта. Конечно, вам все равно понадобится buckets-o-RAM, поэтому подразумевается x64 ...

        ushort[][] arr = new ushort[size][];
        for(int i = 0 ; i < size ; i++) {
            arr[i] = new ushort[size];
        }

Кроме того, вы можете посмотреть на разреженные массивы, eta-векторы и все такое.

5
ответ дан 9 December 2019 в 22:32
поделиться

Причина, по которой вы не можете приблизиться даже к выделению 2 ГБ в 32-битной Windows, заключается в том, что массивы в CLR размещены в непрерывной памяти. В 32-битной Windows у вас настолько ограниченное адресное пространство, что вы не найдете ничего похожего на 2-гигабайтную дыру в виртуальном адресном пространстве процесса. Ваши эксперименты показывают, что наибольший размер доступного адресного пространства составляет 650 МБ. Переход на 64-битную Windows должен, по крайней мере, позволить вам использовать полное выделение 2 ГБ.

Обратите внимание, что ограничение виртуального адресного пространства в 32-битной Windows не имеет ничего общего с объемом физической памяти вашего компьютера, в вашем случае 3Гб. Вместо этого ограничение вызвано количеством бит, которые ЦП использует для адресации адресов памяти. 32-битная Windows использует, что неудивительно, 32 бита для доступа к каждому адресу памяти, что дает общее адресуемое пространство памяти в 4 Гбайт. По умолчанию Windows оставляет 2 ГБ для себя и предоставляет 2 ГБ для текущего процесса, поэтому вы можете понять, почему CLR не найдет ничего похожего на выделение 2 ГБ. С помощью некоторых уловок вы можете изменить распределение ОС / пользователей, чтобы Windows оставила себе только 1 ГБ и предоставила выполняющемуся процессу 3 ГБ, что может помочь. Однако в 64-битных окнах адресуемая память, назначаемая каждому процессу, увеличивается до 8 терабайт, так что здесь CLR почти наверняка сможет использовать полные выделения 2 ГБ для массивов.

4
ответ дан 9 December 2019 в 22:32
поделиться

Для исключения OutOfMemoryException прочтите эту ветку (особенно ответ nobugz и Брайана Расмуссена):
Microsoft Visual C # 2008 Сокращение количества загруженных dll

0
ответ дан 9 December 2019 в 22:32
поделиться

Если разреженный массив не применяется, возможно, лучше просто сделать это на C / C ++ с API платформы, относящейся к файлу с отображением памяти: http://en.wikipedia.org/wiki/Memory-mapped_file

0
ответ дан 9 December 2019 в 22:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: