DataTable огромное потребление памяти

Я загружаю данные CSV из файлов в таблицу данных для обработки.

Проблема в том, что я хочу обработать несколько файлов, и мои тесты с datatable показывают мне огромное потребление памяти, которое я тестировал с файлом csv 37 МБ, и память выросла до 240 МБ, что является очень большим ИМХО. Я читал, что в таблице данных есть накладные расходы, и я мог бы жить с размером около 70 МБ, но не 240 МБ, что означает, что это в шесть раз больше исходного размера. Я читал здесь, что таблицам данных требуется больше памяти, чем POCO, но эта разница слишком велика.

Поставил профайлер памяти и посмотрел, есть ли у меня утечки памяти и где память. Я обнаружил, что столбцы данных имеют от 6 МБ до 19 МБ, заполненные строками, а таблица данных содержит около 20 столбцов. Значения хранятся в столбцах? Почему уходит столько памяти, что можно сделать, чтобы уменьшить потребление памяти. При таком потреблении памяти таблицы данных кажутся непригодными для использования.

Были ли у кого-нибудь такие проблемы с таблицами данных, или я что-то делаю не так?

PS: Я попробовал файл размером 70 МБ, и таблица данных выросла до 500 МБ!

Хорошо, вот небольшой тестовый пример: csv-файл 37 МБ (21 столбец) позволил увеличить память до 179 МБ.

    private static DataTable ReadCsv()
    {
        DataTable table = new DataTable();
        table.BeginLoadData();

        using (var reader = new StreamReader(File.OpenRead(@"C:\Develop\Tests\csv-Data\testdaten\test.csv")))
        {               
            int y = 0;
            int columnsCount = 0;
            while (!reader.EndOfStream)
            {
                var line = reader.ReadLine();
                var values = line.Split(',');

                if (y == 0)
                {
                    columnsCount = values.Count();
                    // create columns
                    for (int x = 0; x < columnsCount; x++)
                    {
                        table.Columns.Add(new DataColumn(values[x], typeof(string)));
                    }
                }
                else
                {
                    if (values.Length == columnsCount)
                    {
                        // add the data
                        table.Rows.Add(values);
                    }
                }

                y++;
            }

            table.EndLoadData();
            table.AcceptChanges();

        }

        return table;
    }

person JohnnyBravo75    schedule 26.08.2013    source источник
comment
вы хотите, чтобы мы угадывали, или вы покажете нам какой-нибудь код, чтобы мы посмотрели?   -  person Ehsan    schedule 26.08.2013
comment
Думаю, в вашем коде должны быть какие-то другие объекты?   -  person King King    schedule 26.08.2013
comment
Память дешевая, но: Возможно, это поможет вам найти более эффективное решение для памяти: stackoverflow.com/questions/275269/   -  person dcaswell    schedule 26.08.2013
comment
@ user814064 Память дешевая? В самом деле? Сегодня мы используем компьютеры 8GB RAM and more, это правда, но есть еще много других, использующих компьютеры 2GB RAM and less. Я не думаю, что приложение, потребляющее 2xx МБ ОЗУ, является тривиальной проблемой, если фактические данные составляют всего 2x МБ.   -  person King King    schedule 26.08.2013
comment
Да, действительно. Здесь никто не подумал, что они сталкиваются с какой-либо ценой. Я могу использовать 256 мегабайт памяти в течение нескольких секунд (или нескольких минут) на моем компьютере, не видя огромных затрат. И я предоставил ссылку на полезный пост, в котором объясняется, почему таблицы данных имеют большой объем памяти.   -  person dcaswell    schedule 26.08.2013


Ответы (2)


DataSet и его дочерние элементы DataTable, DataRow и т. Д. Составляют реляционную базу данных в памяти. Это связано с большими накладными расходами (хотя это действительно делает [некоторые] вещи очень удобными.

Если проблема с памятью,

  • Создайте объекты домена для представления каждой строки в вашем CSV-файле с типизированными свойствами.
  • Создайте собственную коллекцию (или просто используйте IList<T>, чтобы хранить их
  • Alternatively, build a light-weight class with the basic semantics of a DataTable:
    • the ability to select a row by number
    • возможность выбора столбца в строке по номеру строки и имени или номеру столбца.
    • Возможность знать упорядоченный набор имен столбцов
    • Бонус: возможность выбрать столбец по имени или порядковому номеру и получить список его значений, по одному в каждой строке.

Вы уверены, что вам нужно представление файлов CSV в памяти? Не могли бы вы получить к ним доступ через IDataReader Fast CSV Reader, например, с помощью ?

person Nicholas Carey    schedule 26.08.2013
comment
Да, но множителя 6-7 быть не может. В моем коде должна быть проблема, иначе таблицы данных станут непригодным для использования дерьмом. Вот почему я попросил статистические / опытные значения других пользователей для сравнения. Таких накладных расходов нет ни в одной базе данных. Если я помещу их в Sqlite, он не станет таким большим. Я написал свой собственный csv-ридер, AdoAdapter, XmlReader, и разработал приложение для работы с таблицами данных в памяти, и при вычислении коэффициента два оно будет работать. Но эти накладные расходы разрушат мой дизайн. Какой опыт у других пользователей? - person JohnnyBravo75; 27.08.2013

DataTables - это универсальное решение для помещения табличных данных в память и добавления множества функций, связанных с таблицами. Если накладные расходы для вас неприемлемы, у вас есть возможность: 1) написать свой собственный класс DataTable, который устраняет накладные расходы, которые вам не нужны 2) использовать альтернативное представление, которое по-прежнему выполняет то, что вам нужно, возможно, основанное на POCO, или, возможно, XMLDocument (Может быть столько же накладных расходов, может и больше, никогда особо не беспокоился об этом). 3) Прекратите попытки загрузить все в память и просто заносите данные по мере необходимости из внешнего хранилища.

person Gary Walker    schedule 26.08.2013
comment
1 Alread пробовал использовать данные Silverlight от Telerik (blogs.telerik.com/vladimirenchev/posts/09-04-23/), это НЕ легкий вес, он потребляет гораздо больше памяти. Проблема в том, что если вам нужны возможности редактирования, они не могут быть легковесными. В противном случае использование списка словарей более легкое, это моя единственная надежда. - person JohnnyBravo75; 27.08.2013
comment
2. POCO based не является альтернативой, потому что у меня нет специальных данных. У всех данных другая структура. 3. Да, вот что я оцениваю. Проблема в том, что мне нужно обрабатывать данные, создавать ключевые столбцы / индексы, сортировать их ... Возможно, облегченная база данных, такая как sqlite, - это то, что нужно. - person JohnnyBravo75; 27.08.2013
comment
Это очень похоже на мой вариант 3. Есть несколько вариантов базы данных. Облегченный вариант может быть хорошим выбором, или вам может потребоваться что-то более масштабируемое, но базы данных - это в значительной степени одна из первых вещей, которые вы должны рассмотреть, когда ваша информация не помещается в память или когда вам нужно постоянное хранилище. Это то, что они делают. Если вы внесете изменения сейчас, положительным моментом станет то, что, продолжая добавлять данные, вы не просто внезапно столкнетесь с проблемой. - person Gary Walker; 27.08.2013
comment
Просто мысль. Вы вызывали BeginLoadData () в своем DataTable - никогда не сравнивали накладные расходы лично, и я полагаю, я просто предположил, что вы бы попробовали это. Не забывайте EndLoadData () - person Gary Walker; 27.08.2013
comment
Да, я пробовал BeginLoadData () и EndLoadData (), но они не имели никакого значения. Я показал образец кода ... - person JohnnyBravo75; 28.08.2013
comment
И последнее: попробуйте вызвать сборщик мусора после загрузки. Проблема может заключаться в большом количестве неиспользуемых временных объектов. Повторите тест, но вызовите GC после каждой 1000 строк, посмотрите, совпадают ли результаты - это может быть иначе, поскольку GC может не возвращать память обратно в O / S, принудительные вызовы GC могут предотвратить использование дополнительной памяти в первую очередь - - повторные вызовы GC определенно не рекомендуются на практике, но вы бы знали, действительно ли это проблема. - person Gary Walker; 28.08.2013
comment
Привет, тоже пробовал, но был освобожден только тогда, когда datatable очищен (необходимо, только удаление не помогает) и удален, тогда вся память освобождается. - person JohnnyBravo75; 28.08.2013