Советы по работе с огромными рабочими наборами оперативной памяти - PullRequest
4 голосов
/ 29 января 2010

Я работаю над приложением .Net 3.5, разработанным специально для мощного ПК, который выполняет множество операций с данными и вычислений. Недавно я столкнулся с необходимостью двумерного массива объектов размером 4000 x 5000, который очень велик для 32-битного ПК и дает мне исключение OutOfMemoryException. Единственный способ избежать использования такого массива - это идти по очень сложной, трудоемкой дороге, наполненной болью и страданиями.

Есть ли какие-нибудь советы или хитрости, которые профессионалы используют для работы с большими рабочими наборами оперативной памяти? Знаете ли вы какие-либо библиотеки, которые будут полезны (особенно для .Net)? Есть ли способ заставить Windows выделить больше оперативной памяти для моего процесса?

EDIT: Массив, который я использую, будет содержать в основном нулевые ссылки, и я использую массив для отслеживания соседних объектов. Видя, что большинство из них являются нулевыми ссылками, я также предположил бы, что есть более эффективный подход для отслеживания соседних объектов, поиска соседа для любого данного объекта и т. Д.

Ответы [ 7 ]

7 голосов
/ 30 января 2010

Судя по вашим комментариям, думаю, теперь я могу ответить на ваш вопрос. Если большинство ссылок пустые, вы можете хешировать ключи в таблицу, которая, в свою очередь, указывает на ваши элементы. В хэш-карте есть постоянное время O (1), и вам не придется беспокоиться о столкновениях клавиш, потому что каждая пара [x, y] уникальна. Вам также не придется беспокоиться о конфликтах памяти, так как большинство ссылок имеют значение null.

1 голос
/ 30 января 2010

Если большинство ваших элементов нулевые, то, возможно, вам вообще не нужно создавать массив.

Джон предлагает один подход, который будет работать - реализация разреженного массива с использованием связанных списков. Вот еще один:

public struct CellLocation
{
   int Row;
   int Column;
}

public class Element
{
   public Element(int row, int column)
   {
      Location = new CellLocation {Row = row, Column=column};
   }

   public readonly Location { get; private set; }

   // your class's other properties and methods go here
}

Теперь вы можете хранить Element объектов в Dictionary<CellLocation, Element>. Фактически, я бы поместил этот словарь в собственный класс, чтобы он мог реализовывать такие методы, как:

public IEnumerable<Element> AdjacentElements(Element elm)
{
   for (int row = -1; row <= 1; row++)
   {
      for (int column = -1; column <= 1; column++)
      {
         // elm isn't adjacent to itself
         if (row == 0 && column == 0)
         {
            continue;
         }
         CellLocation key = new CellLocation { 
            Row=elm.Location.Row + row, 
            Column=elm.Location.Column + column 
         };
         if (!Cells.ContainsKey(key))
         {
            continue;
         }
         yield return Cells[key];
      }
   }
}

Существуют операции, для которых это может быть быстрее, чем разреженный массив. Чтобы найти элемент в одной строке и столбце, разреженному массиву все еще необходимо выполнить линейный поиск, чтобы найти строку, а затем другой линейный поиск, чтобы найти столбец в этой строке, тогда как этот метод может найти элемент с одним поиском в хеш-таблица.

Есть также обстоятельства, при которых это будет существенно медленнее. Чтобы найти все элементы в строке, требуется столько же поисков в хеш-таблицах, сколько в строке есть ячеек, в то время как выполнение этого с разреженным массивом влечет за собой обход связанного списка.

1 голос
/ 30 января 2010

Вы можете эффективно хранить решетчатую структуру, где большинство элементов равно нулю в разреженном массиве. Они могут быть реализованы различными способами, но обычно используют модифицированные связанные списки для строк и столбцов. Здесь есть хорошее введение в тему здесь .

1 голос
/ 30 января 2010

Ну, одна мысль - вместо этого удалить двумерный массив для базы данных. Нечто подобное SQLite занимает небольшую площадь и может быть легко развернуто с приложением. Для этого есть даже C # оболочка .

SQLite будет читать эти данные из одного файла. Таким образом, чтение и запись с диска может привести к снижению производительности. Хотя, насколько сильно от этого зависит производительность, зависит от характера приложения. Например, поиск по индексу должен быть быстрым. Но массивные вычисления по всей базе данных, безусловно, будут медленнее. Так что ... я не знаю, но, может быть, стоит подумать.

0 голосов
/ 30 января 2010

Похоже, что вы на самом деле делаете матрицу смежности. Если это так, и лежащий в основе граф разрежен, то, вероятно, было бы лучше переключиться на список смежности. http://en.wikipedia.org/wiki/Adjacency_list

0 голосов
/ 30 января 2010

Существует 2 «простых» направления на уровне ОС или процесса.

  1. Добавьте переключатель / 3GB в ваш boot.ini и измените ваше приложение для использования / LARGEADDRESSAWARE .Вы немедленно получаете дополнительный 1G виртуального адресного пространства, но не без компромисса .Хороший шанс, что это правильный выбор для вас.
  2. Часто проблема заключается не в нехватке памяти, а в ее фрагментации - кажется, также имеет отношение к вашему контексту (огромные последовательные массивы).Некоторое время назад я выложил в сеть некоторые методы, которые помогли мне бороться с фрагментацией для нативного кода, - по крайней мере, частично применимые к управляемым.
0 голосов
/ 30 января 2010

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

только мои 2цента ...

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...