web-dev-qa-db-fra.com

Comment les champs statiques fonctionnent-ils exactement en interne?

Dis que tu as une classe, 

class Foo
{
    public static bar;
}

Quand tu dis:

new Foo();

Je peux imaginer qu'en mémoire, un espace est réservé à cet objet. 

... et quand vous dites encore:

new Foo(); 

... bien maintenant vous avez un autre espace disponible pour l'objet.

Cependant, où habite exactement le champ statique?

Ce que j'essaie vraiment d'apprendre, c'est:

Comment les références aux objets font-elles référence au même champ que les objets qu'elles référencent?  

55
Koray Tugay

Bien que les détails exacts du système de types dépendent de la mise en oeuvre, permettez-moi d'entrer dans les détails, mais pas seulement en déclarant que cela dépend et vous ne devriez pas vous en soucier. Je vais décrire comment cela fonctionne approximativement dans l'implémentation de Microsoft (.NET) selon le livre CLR via C # de Jeffrey Richter et l'article Voir Comment le CLR crée-t-il des objets d'exécution? par Hanu Kommalapati et al. ( Version originale de MSDN de mai 2005 ).


Disons que vous avez un cours:

class Foo
{
    // Instance fields
    string myBar = "Foobar";
    int myNum;

    // Static fields
    static string bar = "Foobar";
    static int num;
}

Foo myFoo = new Foo();
Type typeOfFoo = typeof(Foo);

Où vivent les champs d'instance?

Chaque fois que vous dites new Foo(), l'espace est alloué et initialisé pour l'instance d'objet, et le constructeur est appelé. Cette instance est représentée par instance de Foo dans l'image ci-dessous. Telle instance ne contient que les champs d’instance de la classe (dans ce cas, myBar et myNum), ainsi que pour les objets alloués sur le segment de mémoire, deux champs supplémentaires utilisés par le runtime (Sync block index et Type handle). Le descripteur de type est un pointeur sur un objet Type qui décrit le type de l'instance, dans ce cas type de Foo _.

Lorsque vous dites à nouveau new Foo(), un nouvel espace est alloué qui contiendra à nouveau un espace pour les champs d'instance du type. Comme vous pouvez le constater, les champs d'instance sont associés à l'objet instances.

Le moteur d'exécution place chaque champ d'instance à un décalage fixe par rapport au début des données de l'objet. Par exemple, myBar pourrait vivre à l'offset +4. L'adresse du champ d'instance est simplement l'adresse de l'objet plus le décalage du champ.

Où vivent les champs statiques?

Les champs statiques en C # et Java ne sont associés à aucune instance d'objet, mais à un type. Les classes, les structures et les énumérations sont des exemples de types. Une seule fois (par type) un espace est alloué pour contenir les valeurs des champs statiques. Il serait judicieux d'allouer de l'espace pour les champs statiques dans la structure Type qui décrit le type, car il n'y a également qu'un seul objet Type par type. C'est l'approche adoptée par C # et Java.

L'objet Type1 est créé lorsque le type est chargé par le moteur d'exécution. Cette structure contient toutes sortes d'informations nécessaires pour que le moteur d'exécution puisse allouer de nouvelles instances, appeler des méthodes et effectuer des transtes, entre autres. Il contient également l'espace pour les champs statiques, dans ce cas, bar et num.

Le moteur d'exécution a placé chaque champ statique à un certain décalage par rapport au début des données du type. Ceci est différent pour chaque type. Par exemple, bar pourrait vivre au décalage +64. L'adresse du champ statique est l'adresse de l'objet Type plus le décalage du champ. Le type est connu statiquement.

Displays some object structures, and their relationships.

1) Dans Microsoft .NET, plusieurs structures différentes décrivent un type, telles que les structures MethodTable et EEClass.

98

Cela dépend complètement de l'implémentation en question. Pour C # et Java, le moteur d'exécution est autorisé à déterminer où stocker la mémoire pour la variable. Pour le langage C et la plupart des langages compilés, le compilateur effectue cette détermination.

Cela étant dit, en pratique, peu importe . L'utilisation déterminée par la spécification, vous êtes donc libre d'utiliser la variable en sachant que le comportement sera garanti.

16
Reed Copsey

Pour Java, les objets référencés par des champs statiques résideront sur le tas comme d’autres objets:

Le segment de mémoire est la zone de données d'exécution à partir de laquelle la mémoire est allouée pour toutes les instances de classe et les tableaux.

Le champ sera initialisé (si la déclaration contient une initialisation) lorsque la classe est chargée , ce qui se produit immédiatement avant la première occurrence de l'un des événements suivants:

  • une instance de la classe est créée.
  • une méthode statique déclarée par la classe est invoquée.
  • un champ statique déclaré par la classe est attribué.
  • un champ statique déclaré par la classe est utilisé et le champ n'est pas une variable constante (§4.12.4).

L'accès au champ statique se fait via 2 instructions spéciales de la machine virtuelle Java, getstatic et putstatic . Mais à part cette distinction, les champs statiques sont similaires aux champs non statiques.

5
assylias

Cela varie énormément d'une langue à l'autre et peut même varier énormément d'une plateforme à l'autre ...

Par exemple, du côté de .NET, les membres statiques sont "associés" à la définition EEClass gouvernante, qui peut être un membre alloué en tasOUa "alloué" (la spécification C # ne 'spécifiez pas le comportement du tas/pile, c'est un détail d'implémentation de la VM)

5
JerKimball

Il peut y avoir des exceptions, mais pour les types de référence, le mot clé new- crée généralement un objet dans une structure de données interne appelée "tas". Le tas est géré par le CLR (Common Language Runtime). Que vous ayez un membre statique ou d'instance ou une variable locale, cela ne fait aucune différence.

La différence entre les membres statiques et les membres d'instance (ceux sans le mot clé static) réside dans le fait que les membres statiques n'existent qu'une fois par type (class, struct) et que les membres d'instance existent une fois par instance.

C'est seulement la référence qui est statique ou non; cette distinction ne s'applique pas à l'objet référencé (sauf si l'objet est un type valeur). Un membre statique, un membre d'instance et une variable locale peuvent tous référencer le même objet.

5

Je ne connais que C #, et voici ce que je comprends:

Ensuite, votre programme démarre, il charge tous les assemblys associés dans un AppDomain . Lorsque l'assambly est chargé, tous les constructeurs statiques sont appelés, y compris les champs statiques. Ils vivront là-bas, et le seul moyen de les décharger est de décharger AppDomain.

4
Jens Kloster

Les membres statiques et les constantes sont stockés sur le tas. Contrairement aux objets sur le tas qui peuvent obtenir un ramassage des ordures, les membres statiques et les constantes restent jusqu'à ce que Appdomain soit détruit. Par conséquent, une fois doit être prudent dans le traitement des champs statiques

2
Ashish Gupta

Les variables statiques appartiennent à la classe et non à l'objet. Il n'y a donc qu'une seule variable bar en mémoire, même si vous initialisez des milliers d'instants de Foo.

1
Can Geliş

Par spécification, les variables statiques sont stockées dans Constant Pool . JVM stocke cette information dans la génération permanente.

1
Mikhail

Cela dépend de la langue à la langue ou du concepteur de la langue. Si je parle de Java, les membres statiques sont stockés dans la zone Méthode de la machine virtuelle Java et tous les objets leur sont liés. Une autre chose qu'il est très important de savoir, c'est que nous pouvons accéder au membre de données statique sans créer l'objet de la classe. Cela signifie que l'allocation de mémoire aux membres de données statiques ne dépend pas de la création de l'objet de cette classe. classe.

1
Jatin Khurana

En général, les variables statiques sont stockées sur le segment de données de la mémoire de programme . Ainsi, pour chaque classe créée/en cours d'exécution du programme, la variable statique sera créée sur le segment de données et toutes les autres variables seront initialisées dans le segment de code .

donc en gros c'est comme

+++++++++++++++++++++++++++++++++++++
+ DATA Segment
+   -static vars
+   
+----------------------------------
+  instances | instances | instances|
+            |           |          |

ici, une seule zone est partagée entre les instances.

de wikipedia "La zone de données contient des variables globales et statiques utilisées par le programme qui sont:
explicitement initialisé avec une valeur ".

0
Jitendra