Obtenir la taille «optimiste» de l’object géré en mémoire

Premièrement, je suis au courant de nombreuses questions posées sur le sujet: 1 2 3 4 5 . Les approches proposées & pourquoi pas:

  • Marshal.SizeOf () 1 – ne fonctionne pas pour les types gérés.
  • GC.GetTotalMemory 1 2 – prédisposition aux conditions de concurrence.
  • Sérialisation 1 2 3 4 – c’est assez proche, mais les champs automatiques peuvent être problématiques, ainsi que les propriétés sans passeur public. En outre, les performances ne sont pas optimales.
  • Profilage de code à l’aide de SOS 1 2 et d’autres outils – excellent, mais pas pour l’exécution.

En raison du remplissage et des problèmes publiés 1 2 3 , semble-t-il, il n’existe pas de solution optimale, mais plutôt un compromis entre précision, performances et gabarit de code.

Cependant, j’avais besoin d’une méthode simple pour compter l’utilisation de mémoire optimiste (minimum), c’est-à-dire que je veux savoir que l’object occupe au moins autant . La raison en est que j’ai dans l’environnement des types possédant plusieurs collections, parfois nestedes, et que je veux me rapprocher rapidement, qu’un object se rapproche de 0,5 Go en mémoire, etc.

Il y a ce que je suis venu avec et mes questions:

  1. J’attends vos reflections et vos suggestions sur ce qui peut être amélioré.
  2. En particulier, je recherche une mémoire qui n’est pas prise en compte dans ce code et qui pourrait l’être (sans écrire plus de 200 lignes de code pour cela).
  3. Je ne parviens pas à obtenir les champs générés automatiquement (propriété __BackingField ) pour le type hérité, alors que cela fonctionne __BackingField pour les champs de sauvegarde non hérités. J’ai cherché le BindingFlag approprié, mais je n’ai pas pu en trouver un.

     public static long SizeInBytes(this T someObject) { var temp = new Size(someObject); var tempSize = temp.GetSizeInBytes(); return tempSize; } ///  /// A way to estimate the in-memory size af any menaged object ///  ///  private sealed class Size { private static readonly int PointerSize = Environment.Is64BitOperatingSystem ? sizeof(long) : sizeof(int); private readonly TT _obj; private readonly HashSet _references; public Size(TT obj) { _obj = obj; _references = new HashSet { _obj }; } public long GetSizeInBytes() { return GetSizeInBytes(_obj); } private long GetSizeInBytes(T obj) { if (obj == null) return sizeof(int); var type = obj.GetType(); if (type.IsPrimitive) { switch (Type.GetTypeCode(type)) { case TypeCode.Boolean: case TypeCode.Byte: case TypeCode.SByte: return sizeof(byte); case TypeCode.Char: return sizeof(char); case TypeCode.Single: return sizeof(float); case TypeCode.Double: return sizeof(double); case TypeCode.Int16: case TypeCode.UInt16: return sizeof(short); case TypeCode.Int32: case TypeCode.UInt32: return sizeof(int); case TypeCode.Int64: case TypeCode.UInt64: default: return sizeof(long); } } if (obj is decimal) { return sizeof(decimal); } if (obj is ssortingng) { return sizeof(char) * obj.ToSsortingng().Length; } if (type.IsEnum) { return sizeof(int); } if (type.IsArray) { long sizeTemp = PointerSize; var casted = (IEnumerable)obj; foreach (var item in casted) { sizeTemp += GetSizeInBytes(item); } return sizeTemp; } if (obj is Pointer) { return PointerSize; } long size = 0; var t = type; while (t != null) { size += PointerSize; var fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); foreach (var field in fields) { var tempVal = field.GetValue(obj); if (!_references.Contains(tempVal)) { _references.Add(tempVal); size += GetSizeInBytes(tempVal); } } t = t.BaseType; } return size; } } 

[MODIFIER]

Cette question a abouti à l’ article de Nuget et cp

Pour répondre à votre troisième question sur l’obtention de champs, vous pouvez obtenir de manière fiable tous les champs dans un type comme celui-ci:

  public static IEnumerable GetAllFields(Type t) { while (t != null) { foreach (FieldInfo field in t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly)) { yield return field; } t = t.BaseType; } } 

Cela fonctionne car GetFields peut renvoyer les champs privés du Type actuel, mais pas les champs privés hérités. vous devez donc parcourir la chaîne d’inheritance en appelant GetFields sur chaque Type .