Fuite de mémoire lors de l'exécution de SqlBulkCopy

c# sql sqlbulkcopy

Question

Je rencontre une mauvaise fuite de mémoire qui se produit dans le code suivant:

 public void BulkInsert(string tableName, IDataReader reader, String connectionString)
    {
        using (var connection = new SqlConnection(connectionString))
        {
            connection.Open();
            using (var bulkCopy = new SqlBulkCopy(connection))
            {
                bulkCopy.DestinationTableName = tableName;
                bulkCopy.BulkCopyTimeout = 900;

                try
                {
                    bulkCopy.WriteToServer(reader);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                finally
                {
                    reader.Close();
                }
            }
        }
    }

Ce segment de code est exécuté des milliers de fois et, en tant que tel, il ne faut qu'une minute pour qu'une exception de mémoire insuffisante se produise. Ants indique que cela est dû au fait que les lignes désignées par IDataReader ne sont pas collectées par le GC. Cependant, lorsque je commente la ligne suivante, il n’ya pas de fuite, c’est la façon dont j’ai isolé le problème en ce qui concerne le code.

bulkCopy.WriteToServer(reader);

Quelqu'un at-il une suggestion quant à la façon de prévenir la fuite de mémoire?

Merci d'avance.

Code d'appel:

 var reader = datatable.CreateDataReader();
 BulkInsert(tablename, reader, connectionString);
 reader.Dispose();
 datatable.Dispose();

Réponse acceptée

Je déteste absolument répondre à ma propre question, mais j’ai finalement trouvé la solution et bien que je me sente bête d’avoir commis cette erreur, je voulais simplement la poster comme solution au cas où quelqu'un d’autre tomberait sur cette question. Personne ne perd donc un temps précieux.

La fuite de mémoire ne concernait pas du tout le segment de code fourni - En fait, ce n'était pas une fuite du tout ...

En examinant l'analyse des performances, j'ai découvert que l'appel BulkCopy était le goulot d'étranglement de tout mon programme. J'ai un modèle Producteur-Consommateur qui l'alimente en DataTables pour l'insérer.

Je pensais que le Memory Profiler me montrait des objets DataTable qui n'étaient pas supprimés lors de l'exécution du code. C'étaient en fait des tables en file d'attente qui attendaient d'être insérées, mais comme je réutilisais des données de test, les tables en file d'attente étaient déjà dans la base de données (et en tant que telles semblaient avoir déjà été insérées).

En commentant la ligne BulkCopy, j'étais en train de supprimer le goulot d'étranglement, les DataTables ont été rapidement supprimées et aucun problème n'a donc été affiché sur le profileur de mémoire. Cela donnait l'impression que la ligne Bulkcopy était en cause.

Lorsque j'ai remplacé le code BulkCopy par un délai de 1 seconde, cela ne constituait pas un goulot d'étranglement suffisant. Ce n’est que lorsque j’ai remplacé BulkCopy par un délai de 5 secondes que j’ai constaté que ma taille de file d’attente Consumer Producer devenait incontrôlable ... C’est pourquoi j’ai manqué rapidement de mémoire.

Merci à tous ceux qui ont pris du temps sur cette question. Je suis désolé, il n'y avait pas de réponse plus intéressante.


Réponse populaire

Vous devrez peut-être éliminer le lecteur pour que le GC puisse le récupérer. Dans votre dernière tentative de blocage pour appeler Dispose.

finally
{
    //reader.Close();
    reader.Dispose();
}


Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi