Pregunta Se lanzó la excepción del tipo 'System.OutOfMemoryException'. C # cuando se usa IDataReader


Tengo una aplicación en la que tengo que obtener una gran cantidad de datos de DB. Como no pudo obtener todas esas filas (está cerca de 2.000.000 de filas ...), lo corté en intervalos, y ejecuté cada vez la consulta SQL y obtuve solo 200,000 filas cada vez.

Yo uso DataTable a la cual ingresé todos los datos (es decir, todas las 2.000.000 filas deberían estar allí).

Las primeras carreras están bien. Luego falla con OutOfMemoryException.

Mi código funciona de la siguiente manera:

private static void RunQueryAndAddToDT(string sql, string lastRowID, SqlConnection conn, DataTable dt, int prevRowCount)
    {
        if (string.IsNullOrEmpty(sql))
        {
            sql = generateSqlQuery(lastRowID);
        }

        if (conn.State == ConnectionState.Closed)
        {
            conn.Open();
        }

        using (IDbCommand cmd2 = conn.CreateCommand())
        {
            cmd2.CommandType = CommandType.Text;
            cmd2.CommandText = sql;
            cmd2.CommandTimeout = 0;

            using (IDataReader reader = cmd2.ExecuteReader())
            {
                while (reader.Read())
                {
                    DataRow row = dt.NewRow();
                    row["RowID"] = reader["RowID"].ToString();
                    row["MyCol"] = reader["MyCol"].ToString();
                    ... //In one of these rows it returns the exception.

                    dt.Rows.Add(row);
                }
            }
        }

        if (conn != null)
        {
            conn.Close();
        }

        if (dt.Rows.Count > prevRowCount)
        {
            lastRowID = dt.Rows[dt.Rows.Count - 1]["RowID"].ToString();
            sql = string.Empty;
            RunQueryAndAddToDT(sql, lastRowID, conn, dt, dt.Rows.Count);
        }
    }

Me parece que el lector sigue recopilando filas, y es por eso que arroja una excepción solo en la tercera o segunda ronda.

¿No debería el Uso limpiar la memoria como está hecha? ¿Qué puede resolver mi problema?

Nota: Debería explicarlo: no tengo más remedio que obtener todas esas filas en la tabla de datos, ya que las manipulo más tarde, y el orden de las filas es importante, y no puedo dividirlo porque a veces tengo tomar los datos de algunas filas y configurarlas en una fila, y así sucesivamente, así que no puedo renunciar a ellas.

Gracias.


6
2017-12-24 11:19


origen


Respuestas:


Compruebe que está creando un proceso de 64 bits, y no uno de 32 bits, que es el modo de compilación predeterminado de Visual Studio. Para hacer esto, haga clic derecho en su proyecto, Propiedades -> Construir -> destino de la plataforma: x64. Como cualquier proceso de 32 bits, las aplicaciones de Visual Studio compiladas en 32 bits tienen un límite de memoria virtual de 2 GB.

Los procesos de 64 bits no tienen esta limitación, ya que usan punteros de 64 bits, por lo que su espacio máximo de direcciones teórico es de 16 exabytes (2 ^ 64). En realidad, Windows x64 limita la memoria virtual de los procesos a 8TB. La solución al problema del límite de memoria es compilar en 64 bits.

Sin embargo, el tamaño del objeto en Visual Studio todavía está limitado a 2 GB, de forma predeterminada. Podrá crear varias matrices cuyo tamaño combinado será superior a 2 GB, pero no puede crear matrices de más de 2 GB de forma predeterminada. Con suerte, si aún desea crear matrices de más de 2 GB, puede hacerlo agregando el siguiente código a su archivo app.config:

<configuration>
  <runtime>
    <gcAllowVeryLargeObjects enabled="true" />
  </runtime>
</configuration>

8
2018-06-26 14:06



Creo que simplemente te quedaste sin memoria porque tu DataTable es tan grande en todas las filas que sigues añadiendo.

Es posible que desee probar un patrón diferente en este caso.

En lugar de almacenar sus filas en una lista (o DataTable), ¿puede simplemente ceder las filas, ya que están disponibles para su uso cuando llegan?


3
2017-12-24 11:23



Dado que estás usando un DataTable, déjame compartir un problema al azar que estaba teniendo con uno. Verifica tus propiedades de compilación. Tuve un problema con una DataTable lanzando una excepción de falta de memoria al azar. Resultó que el objetivo de Build Platform del proyecto estaba configurado para Prefer 32-bit. Una vez que deseleccioné esa opción, la excepción aleatoria de falta de memoria desapareció.


3
2018-03-23 20:32



Está almacenando una copia de los datos en dt. Simplemente está almacenando tanto que la máquina se está quedando sin memoria. Entonces tienes pocas opciones:

  • Aumenta la memoria disponible.
  • Reduzca la cantidad de datos que está recuperando.

Para aumentar la memoria disponible, puede agregar memoria física a la máquina. Tenga en cuenta que un proceso .NET en una máquina de 32 bits no podrá acceder a más de 2 GB de memoria (3 GB si habilita el conmutador de 3 GB en boot.ini) por lo que es posible que deba cambiar a 64 bits (máquina y proceso) si desea utilizar más memoria que esa.

Recuperar menos datos es probablemente el camino a seguir. Dependiendo de lo que intente lograr, es posible que pueda realizar la tarea en subconjuntos de datos (tal vez incluso en filas individuales). Si está realizando algún tipo de agregación (por ejemplo, produciendo un resumen o informe de los datos), puede emplear Mapa reducido.


2
2017-12-24 11:26