¿Cuál es la sobrecarga de memoria de almacenar datos en una.NET DataTable?
memory-management (3)
Estoy tratando de manejar la cantidad de sobrecarga de memoria asociada con .NET DataTable y con DataRows individuales dentro de una tabla.
En otras palabras, ¿cuánta memoria más ocupa una tabla de datos de la que se necesitaría simplemente para almacenar una matriz correctamente tipada de cada columna de datos?
Supongo que habrá una sobrecarga de tabla básica, más una cantidad por columna, y luego una cantidad adicional por fila.
Entonces, ¿puede alguien dar una estimación (y, supongo, una explicación) de cada uno de estos tres tipos de sobrecarga?
Depende de la cantidad de datos y qué tipo de datos está almacenando. Obviamente, cuantos más datos, más memoria. Hay algunos gastos generales asociados con la tabla de datos que lo hace un poco más caro. También debe conocer el gran montón de objetos. Si almacena objetos de más de 85 kb, el objeto se almacenará en LOH. Esto puede causar estragos en su colección de basura ya que requiere una colección completa. Si está listo para probarlo, busque en un generador de perfiles de memoria para ver la huella de memoria de la tabla de datos.
La sobrecarga es bastante baja si no define los índices en las columnas. Puede obtener una huella de memoria muy baja si utiliza el almacenamiento en caché de cadenas: Use un HashSet o un diccionario para usar solo una instancia de cadena de cada valor de cadena. Esto suena raro, pero si obtiene datos de una base de datos y tiene varias filas con el mismo valor de cadena (por ejemplo, "ALFKI"), los valores de cadena son iguales, pero las instancias de cadena no son: la cadena se almacena varias veces en memoria. Si usa por primera vez un HashSet para filtrar instancias duplicadas, efectivamente usa la misma instancia de cadena para el valor de 1 cadena en todas partes en su tabla de datos. Esto puede reducir enormemente la huella de memoria. Por supuesto, si los valores de cadena ya están definidos estáticamente en algún lugar (por lo que no se leen de una fuente externa), no vale la pena el esfuerzo.
Bueno, no olvides que un DataTable
almacena 2? 3? versiones de los datos, originales y actualizadas (¿posiblemente alguna otra?). También tiene muchas referencias, ya que está basado en celdas y boxeo para cualquier tipo de valor . Sería difícil cuantificar la memoria exacta ...
Personalmente, muy rara vez uso DataTable
- las clases de POCO mecanografiadas son una apuesta mucho más sensata desde mi punto de vista. Sin embargo, yo no usaría una matriz (directamente) - List<T>
o BindingList<T>
o similar serían mucho más comunes.
Como medida cruda, puede crear muchas tablas, etc. y observar el uso de la memoria; por ejemplo, lo siguiente muestra un factor ~ 4.3, es decir, más de 4 veces más caro, pero obviamente eso depende mucho del número de columnas frente a las filas frente a las tablas, etc.
// 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();
vs
// 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();
(Residencia en)
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; }
}