Question

Dans la meilleure réponse acceptée à cette question, il y a une explication claire pourquoi la boxe se produit.

Cependant, si je décompile le code (en utilisant Java Decompiler), je ne vois pas l'utilisation de scala.runtime.boxesruntime. De plus, si je profile le code (en utilisant jprofiler), je ne vois aucune instance de boxesruntime.

Alors, comment puis-je vraiment voir une preuve de boxe / déballage se dérouler?

Était-ce utile?

La solution

Dans ce code:

class Foo[T] {
  def bar(i: T) = i
}


object Main {
  def main(args: Array[String]) {
    val f = new Foo[Int]
    f.bar(5)
  }
}

L'invocation de bar Devrait d'abord boxer l'entier. Compilation avec Scala 2.8.1 et en utilisant:

javap -c -l -private -verbose -classpath <dir> Main$

pour voir le bytecode produit pour le main Méthode de la Main Rendement de la classe:

public void main(java.lang.String[]);                                                      
...                                                                                   
   9:   iconst_5                                                                                          
   10:  invokestatic    #24; //Method scala/runtime/BoxesRunTime.boxToInteger:(I)Ljava/lang/Integer;      
   13:  invokevirtual   #28; //Method Foo.bar:(Ljava/lang/Object;)Ljava/lang/Object;        
   16:  pop                                                                                            
   17:  return                                                                                     
...

Vous pouvez voir l'appel à BoxesRunTime Avant l'appel à bar.

BoxesRunTime est un objet qui contient des méthodes de boxe pour les types primitifs, il devrait donc y avoir exactement une instance au total. L'astuce ici est que ce fichier particulier dans la bibliothèque a été écrit en Java, et les conversions sont des méthodes statiques. Pour cette raison, il n'y a pas de cas lors de l'exécution, bien que l'utiliser dans Scala Code a l'impression qu'il s'agissait d'un objet.

Vous devriez probablement rechercher des primitives en boîte (par exemple java.lang.integer) avec JProfile, bien que je ne sache pas comment le JVM fonctionne et si elle peut réécrire le code au moment de l'exécution et l'optimiser pour éviter la boxe. À ma connaissance, cela ne devrait pas appliquer de spécialisation (mais je crois que CLR le fait). Quelques microbenchacs avec et sans la situation de boxe sont une autre façon de comprendre ce qui se passe au moment de l'exécution.

ÉDITER:

Ce qui précède est en supposant qu'un paramètre de type n'a pas été annoté avec le @specialized annotation. Dans ce cas, la boxe / déballage peut être évitée. Certaines classes de la bibliothèque standard sont spécialisées. Voir Ce sid.

Autres conseils

Compte tenu du test suivant.Scala Programme:

object Test {
  def main(args:Array[String]) {
    val list = List(1,5,15)
    val res = list.map(e => e*2).filter(e => e>10)
  }
}

Si je me compile avec scalac -Xprint:jvm Test.scala, Je reçois cet extrait suggérant que la spécialisation se produit (désolé pour une pâte large):

package <empty> {
  final class Test extends java.lang.Object with ScalaObject {
    def main(args: Array[java.lang.String]): Unit = {
      val list: List = immutable.this.List.apply(scala.this.Predef.wrapIntArray(Array[Int]{1, 5, 15}));
      val res: List = list.map({
        (new Test$$anonfun$1(): Function1)
      }, immutable.this.List.canBuildFrom()).$asInstanceOf[scala.collection.TraversableLike]().filter({
        (new Test$$anonfun$2(): Function1)
      }).$asInstanceOf[List]();
      ()
    };
    def this(): object Test = {
      Test.super.this();
      ()
    }
  };
  @SerialVersionUID(0) @serializable final <synthetic> class Test$$anonfun$1 extends scala.runtime.AbstractFunction1$mcII$sp {
    final def apply(e: Int): Int = Test$$anonfun$1.this.apply$mcII$sp(e);
    <specialized> def apply$mcII$sp(v1: Int): Int = v1.*(2);
    final <bridge> def apply(v1: java.lang.Object): java.lang.Object = scala.Int.box(Test$$anonfun$1.this.apply(scala.Int.unbox(v1)));
    def this(): Test$$anonfun$1 = {
      Test$$anonfun$1.super.this();
      ()
    }
  };
  @SerialVersionUID(0) @serializable final <synthetic> class Test$$anonfun$2 extends scala.runtime.AbstractFunction1$mcZI$sp {
    final def apply(e: Int): Boolean = Test$$anonfun$2.this.apply$mcZI$sp(e);
    <specialized> def apply$mcZI$sp(v1: Int): Boolean = v1.>(10);
    final <bridge> def apply(v1: java.lang.Object): java.lang.Object = scala.Boolean.box(Test$$anonfun$2.this.apply(scala.Int.unbox(v1)));
    def this(): Test$$anonfun$2 = {
      Test$$anonfun$2.super.this();
      ()
    }
  }
}

Cela pourrait être la raison pour laquelle vous ne voyez aucune preuve de boxe dans Bytecode ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top