Je télécharge beaucoup de données en boucle, mais après quelques opérations, je les supprime, mais ce que je vois, c’est que l’allocation de mémoire augmente très rapidement, quelques secondes et 1 Go.
using (var contex = new DB) { var inputs = contex.AIMRInputs.Where(x => x.Input_Type == 1); foreach (var input in inputs) { var data = contex.Values.Where(x => x.InputID == input.InputID).OrderBy(x => x.TimeStamp).ToList(); if (data.Count == 0) continue; foreach (var value in data) { Console.WriteLine(Value.property); } data.Clear(); } }
La première chose que vous pouvez faire est de désactiver le suivi des modifications, car vous ne modifiez aucune donnée dans votre code. Cela évite que les objects chargés ne soient attachés au contexte:
Pour DbContext
(EF> = 4.1):
var inputs = contex.AIMRInputs.AsNoTracking() .Where(x => x.Input_Type == 1);
Et:
var data = contex.Values.AsNoTracking() .Where(x => x.InputID == input.InputID) .OrderBy(x => x.TimeStamp) .ToList();
modifier
Pour EF 4.0, vous pouvez laisser vos requêtes telles quelles mais append les éléments suivants comme les deux premières lignes du bloc using
:
contex.AIMRInputs.MergeOption = MergeOption.NoTracking; contex.Values.MergeOption = MergeOption.NoTracking;
Cela désactive le suivi des modifications pour ObjectContext
.
Modifier 2
… mentionnant en particulier le commentaire de @James Reategui selon lequel AsNoTracking
réduit l’encombrement de la mémoire:
Ceci est souvent vrai (comme dans le modèle / requête de cette question) mais pas toujours! En fait, utiliser AsNoTracking
peut être contre-productif en ce qui concerne l’utilisation de la mémoire.
Que fait AsNoTracking
lorsque des objects sont matérialisés en mémoire?
Premièrement: il n’attache pas l’entité au contexte et ne crée donc pas d’entrées dans le gestionnaire d’état du contexte. Ces entrées consumnt de la mémoire. Lors de l’utilisation de POCO, les entrées contiennent un instantané des valeurs de propriété de l’entité lors de son chargement / attachement au contexte – il s’agit en principe d’une copie de toutes les propriétés (scalaires) en plus de l’object lui-même. Ainsi, la mémoire consommée prend (environ) deux fois plus que la taille de l’object lorsque AsNoTracking
n’est pas appliqué.
Deuxièmement: lorsque des entités ne sont pas attachées au contexte, EF ne peut pas tirer parti de l’avantage du mappage d’identité entre valeurs de clé et identités de référence d’object. Cela signifie que les objects avec la même clé seront matérialisés plusieurs fois, ce qui occupera plus de mémoire sans utiliser AsNoTracking
EF garantira qu’une entité ne sera matérialisée qu’une fois par valeur de clé.
Le deuxième sharepointvient particulièrement important lorsque des entités liées sont chargées. Exemple simple:
Dites, nous avons une Order
et une entité Customer
et une commande a une commande client. Disons que l’object Order
a la taille 10 octets et l’object Customer
la taille 20 octets. Maintenant, nous lançons cette requête:
var orderList = context.Orders .Include(o => o.Customer).Take(3).ToList();
Et supposons que toutes les 3 commandes chargées aient le même client atsortingbué. Parce que nous n’avons pas désactivé le suivi, EF va se matérialiser:
Somme: 100 octets
(Par souci de simplicité, je suppose que les entrées de contexte avec les valeurs de propriété copiées ont la même taille que les entités elles-mêmes.)
Maintenant, nous lançons la requête avec un suivi des modifications désactivé:
var orderList = context.Orders.AsNoTracking() .Include(o => o.Customer).Take(3).ToList();
Les données matérialisées sont:
Somme: 90 octets
Ainsi, l’utilisation de la requête AsNoTracking
consum 10 octets de mémoire en moins dans ce cas.
Maintenant, le même calcul avec 5 commandes ( Take(5)
), encore une fois, toutes les commandes ont le même client:
Sans AsNoTracking
:
Somme: 140 octets
Avec AsNoTracking
:
Somme: 150 octets
Cette fois, l’utilisation d’ AsNoTracking
était 10 octets de plus.
Les chiffres ci-dessus sont très approximatifs, mais il existe un seuil de rentabilité où l’utilisation d’ AsNoTracking
peut nécessiter plus de mémoire.
La différence de consommation de mémoire entre l’utilisation d’ AsNoTracking
ou non dépend fortement de la requête, des relations dans le modèle et des données concrètes chargées par la requête. Par exemple: AsNoTracking
toujours mieux en mémoire lorsque les commandes de l’exemple ci-dessus (ou principalement) ont des clients différents.
Conclusion: AsNoTracking
est principalement conçu comme un outil permettant d’améliorer les performances des requêtes, et non l’utilisation de la mémoire. Dans de nombreux cas, cela consumra également moins de mémoire. Mais ne soyez pas surpris si une requête spécifique nécessite plus de mémoire avec AsNoTracking
. En fin de compte, vous devez mesurer l’empreinte mémoire pour une décision solide en faveur ou contre AsNoTracking
.
Une partie si le problème ici pourrait concerner le DataContext. La plupart d’entre eux mettent en cache des informations ou stockent des informations supplémentaires au fur et à mesure de l’exécution de vos requêtes. Par conséquent, l’empreinte mémoire augmente progressivement. Je vérifierais d’abord avec un profileur, mais si tel est votre problème, vous devrez peut-être recréer un nouveau contexte de données après chaque demande X (essayez différentes valeurs de X pour voir ce qui fonctionne le mieux).
J’aimerais également noter que la plupart des gens ont tendance à avoir beaucoup de mémoire. Avant de commencer à utiliser ces types d’optimisation, assurez-vous que vous utilisez plus de mémoire que ce qui est réellement acceptable. Le CPG commence également à effacer la mémoire de manière plus agressive, car vous disposez de moins de mémoire libre. Cela ne dérange pas d’optimiser prématurément (et vous ne devriez pas non plus).