Pregunta

Estoy tratando de controlar la cantidad de sobrecarga de memoria asociada con una .NET DataTable y con DataRows individuales dentro de una tabla.
En otras palabras, ¿cuánta más memoria ocupa una tabla de datos de lo que se necesitaría simplemente para almacenar una matriz de cada columna de datos correctamente tipada?
Supongo que habrá algunos gastos generales básicos de la tabla, más una cantidad por columna, y luego nuevamente una cantidad adicional por fila.

Entonces, ¿alguien puede dar una estimación (y, supongo, una explicación) de cada uno de estos tres tipos de gastos generales?

¿Fue útil?

Solución

Bueno, no olvides que un DataTable almacena 2? 3? versiones de los datos: originales y actualizadas (¿posiblemente una más?). También tiene muchas referencias, ya que se basa en celdas y en el recuadro para cualquier tipo de valor . Sería difícil cuantificar la memoria exacta ...

Personalmente, rara vez uso List<T> - las clases POCO escritas son una apuesta mucho más sensata en mi opinión. Sin embargo, no usaría una matriz (directamente), BindingList<T> o <=> o similar sería mucho más común.

Como medida cruda, podría 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 de la cantidad de columnas frente a filas frente a 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();

(basado 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; }
}

Otros consejos

La sobrecarga es bastante baja si no define índices en columnas. Puede obtener una huella de memoria bastante baja si usa el almacenamiento en caché de cadenas: Use un HashSet o Dictionary para usar solo 1 instancia de cadena de cada valor de cadena. Esto suena extraño, pero si obtiene datos de una base de datos y tiene varias filas con el mismo valor de cadena (por ejemplo, & Quot; ALFKI & Quot;), los valores de cadena son iguales, pero las instancias de cadena no son : la cadena se almacena varias veces en la memoria. Si primero usa un HashSet para filtrar instancias duplicadas, efectivamente usa la misma instancia de cadena para 1 valor de cadena en todas partes en su tabla de datos. Esto puede reducir en gran medida la huella de memoria. Por supuesto, si los valores de cadena ya están definidos estáticamente en alguna parte (por lo que no se leen de una fuente externa), no vale la pena el esfuerzo.

Depende de cuántos datos y qué tipo de datos esté almacenando. Obviamente, cuantos más datos, más memoria. Hay una sobrecarga asociada con la tabla de datos que la hace un poco más cara. También debe tener en cuenta el montón de objetos grandes. Si almacena objetos de más de 85 kb, el objeto se almacenará en el LOH. Esto puede causar estragos en su recolección de basura, ya que requiere una recolecció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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top