7
votes

La variable obtient des ordures recueillies immédiatement après le bloc de capture

Je peux voir ce comportement curieux du collecteur des ordures xxx pré>

si je passe au débogage et que je pose un point d'arrêt sur // 1 foo n'est pas null et sa valeur est "bar" mais dans Point d'arrêt // 2 FOO est null, cela peut être difficile à comprendre pendant que vous êtes débogué. Ma question est de savoir s'il existe des spécifications qui indiquent qu'il s'agit d'un comportement juridique du collecteur des ordures p>

avec cette petite variation, il ne reçoit pas la poubelle collectée: P>

public class A {
    public static void main(String[] args) {

        String foo;
        try {
            foo = "bar";
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        int foobar = 3;
    }
}


16 commentaires

Quel débogueur utilisez-vous?


Quel débogueur utilisez-vous? Ce comportement semble improbable.


Que se passe-t-il si vous ajoutez system.out.println (foo); après le int foobar = 3; assignation mais laissez le point d'arrêt au même endroit?


Je pense que c'est parce que foo n'a pas de valeur initiale.


Je pense que c'est un hapening parce que vous n'utilisez plus FOO plus à // 2 et après. Essayez de mettre un système.out.print (FOO) après // 2 et exécutez à nouveau le débogage.


@Louiswasserman Je reçois en fait le même comportement ...


Même comportement dans Intellij aussi. Voyons ce que le bytecode est.


En réponse à «Si ce n'est plus utilisé à ce stade, comment cela affecterait-il le débogage à ce moment-là?»: Parce que je recherchais une nouvelle API débogage de ses méthodes / rendements


En réponse à "Que se passe-t-il si vous ajoutez System.Out.println (FOO); après l'int Foobar = 3; mission mais laissez le point d'arrêt au même endroit?": Dans ce cas, "FOO 'existe comme prévu, il n'arrive que S'il n'est plus référencé


Quel débogueur? Pas sûr de simplement déboguer Oracle JDK JDK1.6.0_25 de Intellij Idea


Strange j'ai supposé que Javac réutiliserait la tache de variable locale (c'est-à-dire attribuer à la fois FOO et FOOBAR à la variable locale 1), mais cela ne fait pas cela. C'est à dire. La valeur est toujours disponible et non écrasée.


@jaime Votre édition le rend encore plus étrange - bien fait ;-)


Hahah Mais votre dernière réponse a du sens, une exception étant jetée d'un bloc de capture dire implicitement que vous pouvez appeler des méthodes "foo" (c'est-à-dire une totring ()) après le bloc de capture, car il n'y a qu'un seul chemin d'exécution.


@jaime Oui Vous avez raison, avec cette exception supplémentaire foo.tostring () devient une instruction valide après le bloc de capture.


Oui, merci de toute façon, je doute toujours sur la raison pour laquelle le débogueur a les mêmes limitations que l'environnement d'exécution normal où cet appel (Tostring ()) est illégal après le bloc de capture


@jaime n'est pas sûr non plus. J'ai ajouté un autre exemple qui est drôle ;-)


4 Réponses :


9
votes

Dans ce cas, vous n'utilisez pas la variable FOO après la définition, il serait donc légal que le JVM ignore complètement la variable car il n'est jamais utilisé et cela ne changerait pas le résultat de votre programme. < p> Cependant, il est peu probable que cela se produise dans le mode de débogage.

Dans votre cas, FOO ne doit pas obtenir de GC'ed tant qu'il est en portée ou que vous vous en tenez une référence, qui inclut la section après la Essayez / Catch Block.

EDIT

En fait, je reçois le même comportement que ce que vous décrivez dans NetBeans 7.1.1 avec Java 7.0_03 ... < / p>

Un problème peut être que parce que vous ne définissez pas une valeur par défaut sur foo , vous ne pouvez pas l'utiliser après le bloc d'essai / attraper (il ne compilerait pas). < / p>

bytcode

  • avec le code que vous utilisez xxx
    • en utilisant string foo = null; comme première instruction, auquel cas le débogueur voir la valeur après le bloc Type / Catch: xxx

      Je ne suis pas un spécialiste de bytcode, mais ils ont l'air très similaire à celui-ci ...

      conclusion

      ma conclusion personnelle est que pour le débogueur de montrer la valeur de foo , il doit exécuter un foo.tostring () d'une certaine sorte, ce qui n'est pas Une instruction valide après le bloc de capture comme FOO n'aurait peut-être pas été initialisée. Ajouter un system.out.println (foo) dans cette section n'est pas légal (ne compile pas). Le débogueur est un peu perdu quant à ce que la valeur est et montre null .

      pour convaincre que cela n'a rien à voir avec GC, vous pouvez essayer l'exemple suivant: < / p> xxx

      sur la ligne foobar , vous pouvez voir que c contient la barre mais foo shows comme null . Donc, la chaîne est toujours là, mais le débogueur ne peut pas le montrer.

      même plus drôle exemple: xxx

      sur le foobar ligne, foo Affiche comme null , mais list contient "bar" ... sympa.


2 commentaires

Oui c'est vrai si je définis foo sur NULL avant le bloc d'essai, il ne reçoit pas GC'ed, mais comme vous l'avez dit en mode de débogage, je l'ai même besoin.


@jaime no gc n'est jamais exécuté dans ce programme. Ce n'est qu'une question de savoir ce que le débogueur nous montre, les informations sont disponibles dans les deux cas.



2
votes

foo n'a jamais de valeur par défaut et lorsque vous allez à la ligne 2, vous passez en dehors de la portée dans laquelle il a été défini.


2 commentaires

Juste, mais je veux juste le déboguer: * (


Si cela est vrai, n'est-ce pas un comportement très dangereux?



-2
votes

Ce n'est pas un comportement juridique, car le contexte de la méthode principale est toujours en vie. Il ne devrait idéalement pas être gisé que si vous déclarez la chaîne foo dans le bloc d'essai (auquel cas ne sera pas accessible à 2).

J'ai essayé ce code et ça va bien pour moi.


5 commentaires

Tort. Tant que le comportement ne peut être vu du thread d'exécution (il ne peut évidemment pas), il est parfaitement valide pour écraser la valeur, le gc ou autre chose.


Je doute toujours. GC ne peut pas collecter la valeur car il est très possible et utilisé.


Comportement juridique mais obscurément et déroutant à des fins de débogage


Wow, j'ai besoin de rechercher cela plus. Je vais proposer une explication bientôt.


@Sidcool La règle comme-si elle fait preuve d'autre chose. Une analyse de la vie rapide peut facilement montrer que la variable est morte à ce stade, vous pouvez donc l'écraser, le gc ou quoi que ce soit. Aucun programme juridique ne remarquera jamais la différence.



2
votes

Le code octet généré est comme suit:

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String bar
       2: astore_1
       3: iconst_5
       4: istore_2
       5: goto          9
       8: astore_2
       9: iconst_3
      10: istore_2
      11: return
    Exception table:
       from    to  target type
           0     5     8   Class java/lang/Exception


2 commentaires

Consultez ma mise à jour - je ne vois aucune différence avec le bytecode généré lorsque la nourriture est initialement définie sur NULL.


@assylie Eh bien, vous voyez une différence dans le bytecode, mais seulement les attentes. Rien de sortir de l'ordinaire oui.