125 votes

Trouver la taille de l'instance d'objet en octets en c #

Pour toute instance arbitraire (collections d'objets différents, compositions, objets simples, etc.)

Comment puis-je déterminer sa taille en octets?

(J'ai actuellement une collection d'objets divers et j'essaie de déterminer la taille agrégée de celui-ci)

EDIT: Quelqu'un a-t-il écrit une méthode d'extension pour Object capable de le faire? Ce serait très chouette imo.

62voto

Pavel Minaev Points 60647

Tout d'abord, un avertissement: ce qui suit strictement dans le domaine de laide sans-papiers hacks. Ne comptez pas sur ce travail - même si cela fonctionne pour vous maintenant, il peut cesser de fonctionner demain, avec toute personne mineure ou majeure .Mise à jour NET.

Vous pouvez utiliser les informations contenues dans cet article sur CLR internes - dernière, j'ai vérifié, il était encore en vigueur. Voici comment cela est fait (il récupère l'intérieur "de Base de la Taille de l'Instance du" champ via TypeHandle de la type).

object obj = new List<int>(); // whatever you want to get the size of
RuntimeTypeHandle th = obj.GetType().TypeHandle;
int size = *(*(int**)&th + 1);
Console.WriteLine(size);

Cela fonctionne sur 3.5 SP1 32-bit. Je ne suis pas sûr si les tailles sont les mêmes sur 64 bits, vous pourriez avoir à ajuster les types et/ou des compensations si ils ne le sont pas.

Cela fonctionne pour tous "normal", qui de toutes les instances de la même, bien des types définis. Ceux pour qui ce n'est pas vrai, sont des tableaux et chaînes de caractères pour vous, et je crois aussi StringBuilder. Pour eux, vous devrez ajouter la taille de tous les éléments contenus à leur base et la taille de l'instance.

20voto

BlueMonkMN Points 10838

Vous pourrez peut-être approximer la taille en prétendant la sérialiser avec un sérialiseur binaire (mais en acheminant la sortie vers l'oubli) si vous travaillez avec des objets sérialisables.

 class Program
{
    static void Main(string[] args)
    {
        A parent;
        parent = new A(1, "Mike");
        parent.AddChild("Greg");
        parent.AddChild("Peter");
        parent.AddChild("Bobby");

        System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf =
           new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
        SerializationSizer ss = new SerializationSizer();
        bf.Serialize(ss, parent);
        Console.WriteLine("Size of serialized object is {0}", ss.Length);
    }
}

[Serializable()]
class A
{
    int id;
    string name;
    List<B> children;
    public A(int id, string name)
    {
        this.id = id;
        this.name = name;
        children = new List<B>();
    }

    public B AddChild(string name)
    {
        B newItem = new B(this, name);
        children.Add(newItem);
        return newItem;
    }
}

[Serializable()]
class B
{
    A parent;
    string name;
    public B(A parent, string name)
    {
        this.parent = parent;
        this.name = name;
    }
}

class SerializationSizer : System.IO.Stream
{
    private int totalSize;
    public override void Write(byte[] buffer, int offset, int count)
    {
        this.totalSize += count;
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override bool CanSeek
    {
        get { return false; }
    }

    public override bool CanWrite
    {
        get { return true; }
    }

    public override void Flush()
    {
        // Nothing to do
    }

    public override long Length
    {
        get { return totalSize; }
    }

    public override long Position
    {
        get
        {
            throw new NotImplementedException();
        }
        set
        {
            throw new NotImplementedException();
        }
    }

    public override int Read(byte[] buffer, int offset, int count)
    {
        throw new NotImplementedException();
    }

    public override long Seek(long offset, System.IO.SeekOrigin origin)
    {
        throw new NotImplementedException();
    }

    public override void SetLength(long value)
    {
        throw new NotImplementedException();
    }
}
 

5voto

280Z28 Points 49515

Cela ne s'applique pas au courant .NET mise en œuvre, mais une chose à garder à l'esprit avec des déchets collectés et gérés temps d'exécution est la répartition de la taille d'un objet peut changer tout au long de la durée de vie du programme. Par exemple, certaines générations éboueurs (tels que les Générations/Arrière de Comptage de Référence Hybride collecteur) seulement besoin de stocker certaines informations après qu'un objet est déplacé de la pépinière à la maturité de l'espace.

Cela rend impossible la création d'un système fiable, API générique pour exposer la taille de l'objet.

4voto

SLaks Points 391154

C'est impossible à faire à l'exécution.

Il existe cependant plusieurs profileurs de mémoire qui affichent la taille de l'objet.

ÉDITER : vous pouvez écrire un deuxième programme qui profilera le premier à l’aide de l’ API de profilage CLR et communiquera avec lui par l’intermédiaire de la communication à distance ou autre.

2voto

Autant que je sache, vous ne pouvez pas, sans réellement profonde de comptage de la taille de chaque membre en octets. Mais encore une fois, la taille d'un membre (comme des éléments à l'intérieur d'une collection) comptent pour la taille de l'objet, ou un pointeur sur membre comptent dans le calcul de la taille de l'objet? Dépend de comment vous le définissez.

J'ai couru dans cette situation avant, où j'ai voulu limiter les objets dans le cache de mon navigateur basé sur le mémoire qu'ils ont consommé.

Eh bien, si il y a une astuce pour le faire, je me ferais un plaisir de le savoir!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X