Каковы затраты памяти на хранение данных в .NET DataTable?
-
05-07-2019 - |
Вопрос
Я пытаюсь определить объем накладных расходов памяти, связанных с таблицей данных .NET и с отдельными потоками данных внутри таблицы.
Другими словами, насколько больше памяти занимает таблица данных, чем потребовалось бы просто для хранения правильно типизированного массива каждого столбца данных?
Я предполагаю, что будут некоторые накладные расходы на базовую таблицу, плюс некоторая сумма на столбец, а затем снова дополнительная сумма на строку.
Итак, может ли кто-нибудь дать оценку (и, я полагаю, объяснение!) каждого / любого из этих трех видов накладных расходов?
Решение
Что ж, не забывай, что DataTable
магазины 2?3?версии данных - исходная и обновленная (возможно, еще одна?).Он также имеет много ссылок, поскольку основан на ячейках, и боксирование для любых типов значений.Было бы трудно точно определить объем памяти...
Лично я очень редко пользуюсь DataTable
- типизированные классы POCO, на мой взгляд, гораздо более разумный выбор.Однако я бы не стал использовать массив (напрямую) - List<T>
или BindingList<T>
или подобное было бы гораздо более распространенным явлением.
В качестве грубой меры вы могли бы создать множество таблиц и т.д. И посмотреть на использование памяти;например, следующее показывает коэффициент ~ 4,3, т.е.более чем в 4 раза дороже, но, очевидно, это во многом зависит от количества столбцов, строк, таблиц и т. Д:
// takes **roughly** 112Mb (taskman)
List<DataTable> tables = new List<DataTable>();
for (int j = 0; j < 5000; j++)
{
DataTable table = new DataTable("foo");
for (int i = 0; i < 10; i++)
{
table.Columns.Add("Col " + i, i % 2 == 0 ? typeof(int)
: typeof(string));
}
for (int i = 0; i < 100; i++)
{
table.Rows.Add(i, "a", i, "b", i, "c", i, "d", i, "e");
}
tables.Add(table);
}
Console.WriteLine("done");
Console.ReadLine();
против
// takes **roughly** 26Mb (taskman)
List<List<Foo>> lists = new List<List<Foo>>(5000);
for (int j = 0; j < 5000; j++)
{
List<Foo> list = new List<Foo>(100);
for (int i = 0; i < 100; i++)
{
Foo foo = new Foo { Prop1 = "a", Prop3 = "b",
Prop5 = "c", Prop7 = "d", Prop9 = "e"};
foo.Prop0 = foo.Prop2 = foo.Prop4 = foo.Prop6 = foo.Prop8 = i;
list.Add(foo);
}
lists.Add(list);
}
Console.WriteLine("done");
Console.ReadLine();
(на основе)
class Foo
{
public int Prop0 { get; set; }
public string Prop1 { get; set; }
public int Prop2 { get; set; }
public string Prop3 { get; set; }
public int Prop4 { get; set; }
public string Prop5 { get; set; }
public int Prop6 { get; set; }
public string Prop7 { get; set; }
public int Prop8 { get; set; }
public string Prop9 { get; set; }
}
Другие советы
Накладные расходы довольно низкие, если вы не определяете индексы для столбцов. Вы можете получить довольно низкий объем памяти, если используете строковое кэширование: Используйте HashSet или Dictionary, чтобы использовать только 1 строковый экземпляр каждого строкового значения. Это звучит странно, но если вы выбираете данные из базы данных, и у вас есть несколько строк с одинаковым строковым значением (например, & Quot; ALFKI & Quot;), строковые значения равны, но экземпляры строк не : строка хранится несколько раз в памяти. Если вы впервые используете HashSet для фильтрации дублированных экземпляров, вы фактически используете один и тот же экземпляр строки для 1 строкового значения везде в вашей таблице данных. Это может значительно уменьшить объем памяти. Конечно, если строковые значения уже где-то статически определены (поэтому не считываются из внешнего источника), это не стоит усилий. Р>
Это зависит от того, сколько данных и какие данные вы храните. Очевидно, что чем больше данных, тем больше памяти. С данными связаны некоторые накладные расходы, что делает его немного дороже. Вы также должны знать о куче больших объектов. Если вы храните объекты размером более 85 КБ, объект будет сохранен в LOH. Это может нанести ущерб вашей сборке мусора, так как требует полной сборки. Если вы готовы его протестировать, загляните в профилировщик памяти, чтобы посмотреть объем памяти, доступной для данных. Р>